<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 4.2.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/images/logo.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/images/logo.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/images/logo.png">
  <link rel="mask-icon" href="/images/logo.png" color="#222">

<link rel="stylesheet" href="/css/main.css">


<link rel="stylesheet" href="/lib/font-awesome/css/font-awesome.min.css">

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"gitee.com","root":"/","scheme":"Pisces","version":"7.7.2","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":false,"show_result":false,"style":null},"back2top":{"enable":true,"sidebar":false,"scrollpercent":false},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":false,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},"path":"./public/search.xml"};
  </script>

  <meta name="description" content="持续更新">
<meta property="og:type" content="article">
<meta property="og:title" content="前端进阶">
<meta property="og:url" content="https://gitee.com/mamba666/mamba666.git/2020/09/19/%E9%9D%A2%E8%AF%95--js%E9%83%A8%E5%88%86/index.html">
<meta property="og:site_name" content="共你云雨">
<meta property="og:description" content="持续更新">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://gitee.com/images/56.jpg">
<meta property="og:image" content="https://gitee.com/images/61.png">
<meta property="og:image" content="https://gitee.com/images/62.jpg">
<meta property="og:image" content="https://gitee.com/images/57.jpg">
<meta property="og:image" content="https://gitee.com/images/58.jpg">
<meta property="og:image" content="https://gitee.com/images/59.jpg">
<meta property="og:image" content="https://gitee.com/images/60.png">
<meta property="article:published_time" content="2020-09-19T11:02:08.407Z">
<meta property="article:modified_time" content="2020-10-25T11:07:51.239Z">
<meta property="article:author" content="Edison">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://gitee.com/images/56.jpg">

<link rel="canonical" href="https://gitee.com/mamba666/mamba666.git/2020/09/19/%E9%9D%A2%E8%AF%95--js%E9%83%A8%E5%88%86/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true
  };
</script>

  <title>前端进阶 | 共你云雨</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>
	<a href="https://github.com/mamba666" target="_blank" rel="noopener" class="github-corner" aria-label="View source on GitHub"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:#151513; color:#fff; position: absolute; top: 0; border: 0; right: 0;" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <div>
      <a href="/" class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">共你云雨</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
    </div>
  </div>
</div>


<nav class="site-nav">
  
  <ul id="menu" class="menu">
        <li class="menu-item menu-item-home">

    <a href="/" rel="section"><i class="fa fa-fw fa-home"></i>首页</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/tags/" rel="section"><i class="fa fa-fw fa-tags"></i>标签</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/categories/" rel="section"><i class="fa fa-fw fa-th"></i>分类</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/archives/" rel="section"><i class="fa fa-fw fa-archive"></i>归档</a>

  </li>
  </ul>

</nav>
</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content">
            

  <div class="posts-expand">
      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block " lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://gitee.com/mamba666/mamba666.git/2020/09/19/%E9%9D%A2%E8%AF%95--js%E9%83%A8%E5%88%86/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/images/avatar.gif">
      <meta itemprop="name" content="Edison">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="共你云雨">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          前端进阶
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2020-09-19 19:02:08" itemprop="dateCreated datePublished" datetime="2020-09-19T19:02:08+08:00">2020-09-19</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="fa fa-calendar-check-o"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2020-10-25 19:07:51" itemprop="dateModified" datetime="2020-10-25T19:07:51+08:00">2020-10-25</time>
              </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/%E9%9D%A2%E8%AF%95/" itemprop="url" rel="index"><span itemprop="name">面试</span></a>
                </span>
            </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
        <p>持续更新</p>
<a id="more"></a>

<h1 id="原始类型有哪儿几种"><a href="#原始类型有哪儿几种" class="headerlink" title="原始类型有哪儿几种"></a>原始类型有哪儿几种</h1><ul>
<li>boolean、string、null、undefined、number、symbol（es6新增）</li>
<li>原始类型都是值，所以他们都不能调用任何方法（函数）</li>
<li>由于 js 的 number 为浮点型，所以，<code>0.1+0.2 ！= 0.3</code></li>
</ul>
<h1 id="null-是对象吗"><a href="#null-是对象吗" class="headerlink" title="null 是对象吗"></a>null 是对象吗</h1><ul>
<li>null 并不是对象，虽然 <code>typeof(null) =&gt; object</code>。</li>
<li>在 js 早期，用000开头表示对象，但是 null 意思是空，所以也是000开头，所以这实际上是一个 bug 。</li>
</ul>
<h1 id="对象类型和原始类型的不同"><a href="#对象类型和原始类型的不同" class="headerlink" title="对象类型和原始类型的不同"></a>对象类型和原始类型的不同</h1><ul>
<li>所有的原始类型存储的都是值，而对象类型存储的实际上是一个指针，这个指针又指向实际的对象</li>
</ul>
<h1 id="如果函数参数是对象会发生什么"><a href="#如果函数参数是对象会发生什么" class="headerlink" title="如果函数参数是对象会发生什么"></a>如果函数参数是对象会发生什么</h1><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">test</span>(<span class="params">person</span>)</span>&#123;</span><br><span class="line">	person.age=<span class="number">26</span></span><br><span class="line">	person=&#123;</span><br><span class="line">		name:<span class="string">"yyy"</span>,</span><br><span class="line">		age:<span class="number">30</span></span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> person</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> p1=&#123;</span><br><span class="line">	name:<span class="string">"xxx"</span>,</span><br><span class="line">	age:<span class="number">23</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> p2=test(p1)</span><br><span class="line"><span class="built_in">console</span>.log(p1)</span><br><span class="line"><span class="built_in">console</span>.log(p2)</span><br></pre></td></tr></table></figure>

<ol>
<li>观察上面的代码，实际上传入 test 函数的 p1 对象是一个指针。</li>
<li>p1 指向这个指针。</li>
<li>那么分析一下这个流程发生了什么：首先 p1 的 age 属性被改变为26，接着 p1 被赋值了一个新的对象，然后被返回，p2 得到这个返回。看似 p1 和 p2 是相等的，但事实如此吗？</li>
<li>当然错了！要明确，<code>当函数的参数为一个对象的时候，传递的实际上是这个对象的指针的一个副本</code>。</li>
<li>怎么理解呢？画了一张图：</li>
<li><img src="/images/56.jpg" alt></li>
</ol>
<h1 id="typeof-和-instanceof-区别"><a href="#typeof-和-instanceof-区别" class="headerlink" title="typeof 和 instanceof 区别"></a>typeof 和 instanceof 区别</h1><p>typeof：</p>
<ul>
<li>对于原始类型，除了 null 会因为 bug 显示为 object 之外，都可以被正确的显示</li>
<li>对于对象，除了函数会显示为 function 之外，其余均显示为 object</li>
<li>以上可以看出 typeof 用来判断类型的局限性</li>
</ul>
<p>instanceof：</p>
<ul>
<li>instanceof 的判断机制是通过原型链一层一层的往上寻找的</li>
<li>要注意 <code>{} instanceof Object</code> 这种写法会报语法错误，因为 {} 在 js 中同时也表示为空对象，所以报错了。正确写法： <code>({}) instanceof Object</code></li>
<li>由于 instanceof 的机制是通过原型链，所以它不适合于判断原始类型</li>
</ul>
<h1 id="构造函数和原型"><a href="#构造函数和原型" class="headerlink" title="构造函数和原型"></a>构造函数和原型</h1><h2 id="构造函数"><a href="#构造函数" class="headerlink" title="构造函数"></a>构造函数</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// A就是构造函数，里面会有this指针</span></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">A</span>(<span class="params">name</span>) </span>&#123;</span><br><span class="line">	<span class="keyword">this</span>.name = name</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> a = <span class="keyword">new</span> A(<span class="string">"xxx"</span>)</span><br><span class="line">log(a) <span class="comment">//A &#123; name: 'xxx' &#125;</span></span><br></pre></td></tr></table></figure>

<ul>
<li>那么这个 new 到底发生了什么？</li>
</ul>
<ol>
<li>会在内存中创建一个新的存储空间</li>
<li>让构造函数的 this 指向新的存储空间</li>
<li>然后开始赋值（添加属性和方法），这里添加了 name 属性值</li>
<li>返回一个新的实例对象给 a</li>
</ol>
<h2 id="构造函数的成员概念"><a href="#构造函数的成员概念" class="headerlink" title="构造函数的成员概念"></a>构造函数的成员概念</h2><ul>
<li>在构造函数中，里面有属性和方法，这些都是成员。而成员又分为实例成员和静态成员。</li>
<li>实例成员：只能通过实例化出来的对象才可以调用的属性和方法</li>
<li>静态成员：只能被构造函数去调用的属性和方法</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">A</span>(<span class="params">name</span>) </span>&#123;</span><br><span class="line">	<span class="keyword">this</span>.name = name</span><br><span class="line">	<span class="keyword">this</span>.say = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">		log(<span class="number">1</span>)</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line">A.sing = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">	log(<span class="number">2</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> a = <span class="keyword">new</span> A(<span class="string">"xxx"</span>)</span><br><span class="line">log(a.name) <span class="comment">//xxx</span></span><br><span class="line">a.say() <span class="comment">//1</span></span><br><span class="line">a.sing() <span class="comment">//a.sing is not a function</span></span><br><span class="line">A.sing() <span class="comment">//2</span></span><br></pre></td></tr></table></figure>

<h2 id="构造函数存在的问题"><a href="#构造函数存在的问题" class="headerlink" title="构造函数存在的问题"></a>构造函数存在的问题</h2><ul>
<li>之前已经说过了，new 的过程中会创建一个新的存储空间，构造函数的 this 会指向这个新的空间，所以，创建 n 个实例对象，那么就会开辟 n 个新的空间。更加致命的是，如果构造函数中有函数，函数又是对象类型，存储的实际上是一个指针，那么如果构造函数有一个函数方法，那么就是 2n 个新空间，以此类推。致命的是，绝大多数存储空间存储的是一样的东西，就会造成性能上的问题。</li>
</ul>
<h2 id="prototype-amp-proto"><a href="#prototype-amp-proto" class="headerlink" title="prototype &amp; proto"></a>prototype &amp; <strong>proto</strong></h2><ul>
<li>构造函数中存在 prototype</li>
<li>实例对象中存在 <strong>proto</strong></li>
<li>它们的关系：<code>A.prototype===a.__proto__</code></li>
</ul>
<h2 id="constructor-NaN"><a href="#constructor-NaN" class="headerlink" title="constructor"></a>constructor</h2><ul>
<li>既然<code>A.prototype===a.__proto__</code>，那么构造函数 A 和实例对象 a 到底指向的是什么东西呢？</li>
<li>这张图很好的说明了，这个东西的 constructor 又指向了原本的构造函数，而这个东西的 <strong>proto</strong> 的 constructor 指向了 Object 。这其实就涉及到了原型链。<br><img src="/images/61.png" alt></li>
</ul>
<h2 id="原型链"><a href="#原型链" class="headerlink" title="原型链"></a>原型链</h2><ul>
<li>这里用一张图解释，同时也解释了上面的三角关系</li>
</ul>
<p><img src="/images/62.jpg" alt></p>
<h1 id="关于-this-的总结"><a href="#关于-this-的总结" class="headerlink" title="关于 this 的总结"></a>关于 this 的总结</h1><h2 id="指向性"><a href="#指向性" class="headerlink" title="指向性"></a>指向性</h2><ul>
<li>直接调用，this 指向 window</li>
<li>间接调用，this 指向 调用者</li>
<li>构造函数，this 指向构造函数的实例</li>
</ul>
<h2 id="箭头函数中的-this"><a href="#箭头函数中的-this" class="headerlink" title="箭头函数中的 this"></a>箭头函数中的 this</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">a</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">	<span class="keyword">this</span>.x = <span class="number">1</span></span><br><span class="line">	<span class="keyword">return</span> <span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">		<span class="keyword">return</span> <span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">			log(<span class="keyword">this</span>)</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> b = <span class="keyword">new</span> a()</span><br><span class="line">b()() <span class="comment">// a &#123; x: 1 &#125;</span></span><br></pre></td></tr></table></figure>

<ul>
<li>这个 this 指向什么呢？首先要明确：<code>箭头函数中是没有this的，this只取决于包裹箭头函数的第一个普通函数的this</code></li>
<li>箭头函数没有自己的this, 它的this是继承而来; 默认指向在定义它时所处的对象(宿主对象）</li>
<li>箭头函数根本没有自己的this，导致内部的this就是外层代码块的this。</li>
<li><code>所以上面的this最后打印出来就是a这个构造函数</code></li>
</ul>
<h2 id="this-的流程图"><a href="#this-的流程图" class="headerlink" title="this 的流程图"></a>this 的流程图</h2><p>看图即可：<br><img src="/images/57.jpg" alt></p>
<h1 id="和-的区别"><a href="#和-的区别" class="headerlink" title="==和===的区别"></a>==和===的区别</h1><ul>
<li>== 会进行类型的转换，然后再去比较</li>
<li>=== 会从类型、值去比较</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> a = <span class="string">'1'</span>, c = <span class="number">1</span></span><br><span class="line">log(a == c) <span class="comment">// true</span></span><br><span class="line">log(a === c) <span class="comment">// false</span></span><br></pre></td></tr></table></figure>

<h1 id="闭包"><a href="#闭包" class="headerlink" title="闭包"></a>闭包</h1><ul>
<li>定义：函数A中有函数B，B可以访问A中的变量，那么B就是一个闭包</li>
<li>意义：间接访问函数内的变量</li>
</ul>
<p>使用闭包解决经典的 for 循环问题，不使用 let</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">&#x2F;&#x2F; 未使用闭包</span><br><span class="line">for (var i &#x3D; 1; i &lt; 5; i++) &#123;</span><br><span class="line">	setTimeout(function timer() &#123;</span><br><span class="line">		log(i)</span><br><span class="line">	&#125;, i * 1000)</span><br><span class="line">&#125;</span><br><span class="line">&#x2F;&#x2F; 使用闭包</span><br><span class="line">for (var i &#x3D; 1; i &lt; 5; i++) &#123;</span><br><span class="line">	; (function (j) &#123;</span><br><span class="line">		setTimeout(() &#x3D;&gt; &#123;</span><br><span class="line">			log(j)</span><br><span class="line">		&#125;, j * 100)</span><br><span class="line">	&#125;)(i)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h1 id="什么是浅拷贝，以及如何实现"><a href="#什么是浅拷贝，以及如何实现" class="headerlink" title="什么是浅拷贝，以及如何实现"></a>什么是浅拷贝，以及如何实现</h1><blockquote>
<p>在探讨拷贝时，先想想为什么要使用拷贝。因为在 JS 中，对象的操作实际上是在操作指针，所以会造成连锁反应</p>
</blockquote>
<h2 id="Object-assign"><a href="#Object-assign" class="headerlink" title="Object.assign"></a>Object.assign</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> a = &#123;</span><br><span class="line">	x: <span class="number">1</span>,</span><br><span class="line">	y: <span class="number">2</span>,</span><br><span class="line">	z: &#123;</span><br><span class="line">		xx: <span class="number">11</span>,</span><br><span class="line">		yy: <span class="number">22</span></span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> b = <span class="built_in">Object</span>.assign(&#123;&#125;, a)</span><br><span class="line">a.x = <span class="number">1111</span></span><br><span class="line">a.z.xx = <span class="number">1111</span></span><br><span class="line">log(b)</span><br></pre></td></tr></table></figure>

<ul>
<li>观察上面的代码，b 打印出 <code>{ x: 1, y: 2, z: { xx: 1111, yy: 22 } }</code></li>
<li>所以不难发现，b 虽然拷贝了 a 对象，并且 a.x 不能改变 b。但是，a 中的 z 对象，实际上还是一个引用类型，因为通过 a.z.xx 还是可以改变 b</li>
<li>这就是浅拷贝的局限性</li>
</ul>
<h2 id="展开运算符-…"><a href="#展开运算符-…" class="headerlink" title="展开运算符 …"></a>展开运算符 …</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> a = &#123;</span><br><span class="line">	x: <span class="number">1</span>,</span><br><span class="line">	y: <span class="number">2</span>,</span><br><span class="line">	z: &#123;</span><br><span class="line">		xx: <span class="number">11</span>,</span><br><span class="line">		yy: <span class="number">22</span></span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> b = &#123; ...a &#125;</span><br><span class="line">a.x = <span class="number">1111</span></span><br><span class="line">a.z.xx = <span class="number">1111</span></span><br><span class="line">log(b)</span><br></pre></td></tr></table></figure>

<ul>
<li>b 依然打印出 <code>{ x: 1, y: 2, z: { xx: 1111, yy: 22 } }</code></li>
<li>可见，不管什么方法，都解决不了浅拷贝的局限性</li>
</ul>
<h1 id="什么是深拷贝，以及如何实现"><a href="#什么是深拷贝，以及如何实现" class="headerlink" title="什么是深拷贝，以及如何实现"></a>什么是深拷贝，以及如何实现</h1><blockquote>
<p>深拷贝实际上是为了解决浅拷贝的局限性（即不能拷贝对象中的对象）。</p>
</blockquote>
<h2 id="使用JSON-parse"><a href="#使用JSON-parse" class="headerlink" title="使用JSON.parse"></a>使用JSON.parse</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> a = &#123;</span><br><span class="line">	x: <span class="number">1</span>,</span><br><span class="line">	y: <span class="number">2</span>,</span><br><span class="line">	z: &#123;</span><br><span class="line">		xx: <span class="number">11</span>,</span><br><span class="line">		yy: <span class="number">22</span></span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> b = <span class="built_in">JSON</span>.parse(<span class="built_in">JSON</span>.stringify(a))</span><br><span class="line">a.x = <span class="number">1111</span></span><br><span class="line">a.z.xx = <span class="number">1111</span></span><br><span class="line">log(b)</span><br></pre></td></tr></table></figure>

<ul>
<li>这个方法解决了嵌套对象的拷贝问题，那么原理呢？</li>
</ul>
<ol>
<li>首先通过 JSON.stringify(a) 将对象 a 序列化为 JSON 格式的字符串</li>
<li>那么为什么要序列化呢？因为 JS 对象存储的本质上是一个地址，并且在内存中，如果断电的话，就会丢失，那么对象二九不复存在。而序列化的意义就是将对象的内容转换为字符串存储在磁盘上。</li>
<li>最后用 JSON.parse 将 JSON 格式的字符串转换为对象</li>
<li>但是这种方法存在很大的缺陷，不一一列举了</li>
</ol>
<h2 id="使用递归实现简易深拷贝"><a href="#使用递归实现简易深拷贝" class="headerlink" title="使用递归实现简易深拷贝"></a>使用递归实现简易深拷贝</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> a = &#123;</span><br><span class="line">	x: <span class="number">1</span>,</span><br><span class="line">	y: <span class="number">2</span>,</span><br><span class="line">	z: &#123;</span><br><span class="line">		x: <span class="number">11</span>,</span><br><span class="line">		y: <span class="number">22</span>,</span><br><span class="line">		z: &#123;</span><br><span class="line">			x: <span class="number">111</span>,</span><br><span class="line">			y: <span class="number">222</span>,</span><br><span class="line">			z: &#123;</span><br><span class="line">				x: <span class="number">1111</span>,</span><br><span class="line">				y: <span class="number">1111</span></span><br><span class="line">			&#125;</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> o = &#123;&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">deepCopy</span>(<span class="params">newObj, oldObj</span>) </span>&#123;</span><br><span class="line">	<span class="comment">// 首先使用浅拷贝，将oldObj所有属性先赋值到newObj</span></span><br><span class="line">	<span class="built_in">Object</span>.assign(newObj, oldObj)</span><br><span class="line">	<span class="keyword">if</span> (oldObj.z) &#123;</span><br><span class="line">		deepCopy(newObj.z, oldObj.z)</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="keyword">return</span> newObj</span><br><span class="line">&#125;</span><br><span class="line">deepCopy(o, a)</span><br><span class="line">log(o)</span><br></pre></td></tr></table></figure>

<p>思路：</p>
<ol>
<li>使用 Object.assign 将数据进行浅拷贝</li>
<li>然后通过递归在一层一层的去进行浅拷贝</li>
<li>原理就是 Object.assign 只能真正的拷贝第一层，如此往复，就可以看作一个深拷贝了</li>
</ol>
<h2 id="Lodash"><a href="#Lodash" class="headerlink" title="Lodash"></a>Lodash</h2><ul>
<li>因为深拷贝很多学问，所以可以使用一些优秀的 JS 库的方法去进行深拷贝。</li>
<li>在 Lodash 中，<code>_.cloneDeep(value)</code>就是一个深拷贝的方法</li>
</ul>
<h1 id="什么是变量提升"><a href="#什么是变量提升" class="headerlink" title="什么是变量提升"></a>什么是变量提升</h1><ul>
<li>先说一下之前面试遇到的一个问题，如下代码，当初脑袋里想的就是 a=1 前面为什么没有 var、let、const 去定义，就觉得面试题是不是错了</li>
<li>实际上，一个打印会出错，因为 a 确实没有被定义。但是第二个会打印出1，即使 a=1 前没有定义的关键字（var、let、const）</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">log(a)</span><br><span class="line">a=<span class="number">1</span></span><br><span class="line">log(a)</span><br></pre></td></tr></table></figure>

<h2 id="通过一张图解释"><a href="#通过一张图解释" class="headerlink" title="通过一张图解释"></a>通过一张图解释</h2><p><img src="/images/58.jpg" alt></p>
<h1 id="什么是暂时性死区"><a href="#什么是暂时性死区" class="headerlink" title="什么是暂时性死区"></a>什么是暂时性死区</h1><ul>
<li>在使用 let const 声明变量之前，这个变量都是不可使用的（此时只是创建了变量，但实际上还没有被初始化和赋值，所以不可用）。这就叫暂时性死区</li>
</ul>
<h1 id="var-let-const的区别"><a href="#var-let-const的区别" class="headerlink" title="var let const的区别"></a>var let const的区别</h1><p>在前面差不多已经辨析完了。这里只讲讲 const 为什么可以定义常量</p>
<ul>
<li>const 实际上保存的是这个变量所保存的指针，并且这个指针不允许被改动，所以可以定义常量</li>
<li>但是由于是指针，那么如果保存的是一个对象，const 所定义的常量还是被变化</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> a = <span class="number">1</span></span><br><span class="line">a = <span class="number">10</span></span><br><span class="line">log(a) <span class="comment">//报错</span></span><br><span class="line"><span class="keyword">const</span> b = &#123;</span><br><span class="line">	x: <span class="number">1</span></span><br><span class="line">&#125;</span><br><span class="line">b.x = <span class="number">2</span></span><br><span class="line">log(b) <span class="comment">//不报错，正常被修改</span></span><br></pre></td></tr></table></figure>

<h1 id="为什么要使用模块化"><a href="#为什么要使用模块化" class="headerlink" title="为什么要使用模块化"></a>为什么要使用模块化</h1><ol>
<li>解决命名上的冲突</li>
<li>提供代码的可复用性</li>
<li>提高代码的可维护性</li>
</ol>
<h1 id="es6-的模块化"><a href="#es6-的模块化" class="headerlink" title="es6 的模块化"></a>es6 的模块化</h1><blockquote>
<p>重点是 export import 的使用</p>
</blockquote>
<ul>
<li>模块功能主要由两个命令构成：export 和 import。export 命令用于规定模块的对外接口，import 命令用于输入其他模块提供的功能。</li>
</ul>
<h2 id="export"><a href="#export" class="headerlink" title="export"></a>export</h2><h3 id="输出变量"><a href="#输出变量" class="headerlink" title="输出变量"></a>输出变量</h3><ul>
<li>一个模块就是一个独立的文件，外部是无法获取到内部的变量的。如果想要获取模块内的变量，就需要使用 export 输出。如下输出了三个变量<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// profile.js</span></span><br><span class="line"><span class="keyword">var</span> firstName = <span class="string">'Michael'</span></span><br><span class="line"><span class="keyword">var</span> lastName = <span class="string">'Jackson'</span></span><br><span class="line"><span class="keyword">var</span> year = <span class="number">1958</span></span><br><span class="line"><span class="keyword">export</span> &#123; firstName, lastName, year &#125;</span><br></pre></td></tr></table></figure>

</li>
</ul>
<h3 id="输出函数或类"><a href="#输出函数或类" class="headerlink" title="输出函数或类"></a>输出函数或类</h3><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">v1</span>(<span class="params"></span>) </span>&#123; ... &#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">v2</span>(<span class="params"></span>) </span>&#123; ... &#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> &#123;</span><br><span class="line"><span class="comment">// as关键字可以重命名</span></span><br><span class="line">  v1 <span class="keyword">as</span> streamV1,</span><br><span class="line">  v2 <span class="keyword">as</span> streamV2,</span><br><span class="line">  v2 <span class="keyword">as</span> streamLatestVersion</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure>

<ul>
<li>要特别注意，export 输出的是一个接口，而不是具体的值！如下的写法都是错误的</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">export</span> <span class="number">1</span></span><br><span class="line"><span class="comment">// 下面这个正确写法为 export &#123;m&#125;</span></span><br><span class="line"><span class="keyword">let</span> m=<span class="number">1</span></span><br><span class="line"><span class="keyword">export</span> m</span><br></pre></td></tr></table></figure>

<h2 id="import"><a href="#import" class="headerlink" title="import"></a>import</h2><blockquote>
<p>使用export命令定义了模块的对外接口以后，其他 JS 文件就可以通过import命令加载这个模块。</p>
</blockquote>
<ul>
<li>接上面的 profile.js 文件，看看如何引入<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// main.js</span></span><br><span class="line"><span class="comment">//下面代码的import命令，用于加载profile.js文件，并从中输入变量。import命令接受一</span></span><br><span class="line"><span class="comment">//对大括号，里面指定要从其他模块导入的变量名。大括号里面的变量名，必须与被导入模块</span></span><br><span class="line"><span class="comment">//（profile.js）对外接口的名称相同。</span></span><br><span class="line"><span class="keyword">import</span> &#123; firstName, lastName, year &#125; <span class="keyword">from</span> <span class="string">'./profile.js'</span>;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">setName</span>(<span class="params">element</span>) </span>&#123;</span><br><span class="line">  element.textContent = firstName + <span class="string">' '</span> + lastName;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
<li>import 命令输入的变量都是只读的，因为它的本质是输入接口。但是如果是一个对象，就可以修改。不过，这种写法很难查错，建议凡是输入的变量，都当作完全只读，不要轻易改变它的属性。</li>
<li>import后面的from指定模块文件的位置，可以是相对路径，也可以是绝对路径，.js后缀可以省略。</li>
</ul>
<h1 id="Proxy"><a href="#Proxy" class="headerlink" title="Proxy"></a>Proxy</h1><blockquote>
<p>Vue 3.0 使用了 Proxy 代替原有的 Object.defineProperty 来实现数据的响应式</p>
</blockquote>
<ul>
<li>思考几个问题：为什么要替换原有的方法？各自的差异？</li>
<li>最根本的原因就是Proxy无需一层一层的递归为每个属性添加代理，只需要一次即可完成，性能更好</li>
</ul>
<h2 id="Reflect-get"><a href="#Reflect-get" class="headerlink" title="Reflect.get()"></a>Reflect.get()</h2><blockquote>
<p>Reflect.get方法允许你从一个对象中取属性值。</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Object</span></span><br><span class="line"><span class="keyword">let</span> obj = &#123;</span><br><span class="line">	x: <span class="number">1</span>,</span><br><span class="line">	y: <span class="number">2</span></span><br><span class="line">&#125;</span><br><span class="line">log(<span class="built_in">Reflect</span>.get(obj, <span class="string">'x'</span>)) <span class="comment">//1</span></span><br><span class="line"><span class="comment">// Array</span></span><br><span class="line">log(<span class="built_in">Reflect</span>.get([<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>], <span class="number">1</span>)) <span class="comment">//2</span></span><br><span class="line"><span class="comment">// Proxy</span></span><br><span class="line"><span class="comment">// 首先定义一个x对象</span></span><br><span class="line"><span class="keyword">let</span> x = &#123;</span><br><span class="line">	p: <span class="number">1</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 定义一个Proxy对象，Proxy有俩个参数</span></span><br><span class="line"><span class="comment">// target:需要添加的代理对象，这里是x</span></span><br><span class="line"><span class="comment">// handler:自定义对象的操作，这里是get(t,k,r)</span></span><br><span class="line"><span class="keyword">let</span> y = <span class="keyword">new</span> <span class="built_in">Proxy</span>(x, &#123;</span><br><span class="line">	<span class="comment">// get为Proxy通过自定义的对象的操作</span></span><br><span class="line">	<span class="comment">// t:目标对象，这里是x</span></span><br><span class="line">	<span class="comment">// k:在触发这个操作时获取到的属性名，这里是foo</span></span><br><span class="line">	<span class="comment">// r:Proxy或者继承Proxy的对象</span></span><br><span class="line">	<span class="keyword">get</span>(t, k, r) &#123;</span><br><span class="line">		log(t) <span class="comment">//&#123;p:1&#125;</span></span><br><span class="line">		log(k) <span class="comment">//foo</span></span><br><span class="line">		log(r) <span class="comment">//&#123;p:1&#125;</span></span><br><span class="line">		<span class="keyword">return</span> k + <span class="string">'bar'</span></span><br><span class="line">	&#125;</span><br><span class="line">&#125;)</span><br><span class="line">log(<span class="built_in">Reflect</span>.get(y, <span class="string">'foo'</span>))</span><br></pre></td></tr></table></figure>

<h2 id="Reflect-set"><a href="#Reflect-set" class="headerlink" title="Reflect.set()"></a>Reflect.set()</h2><blockquote>
<p>Reflect.set 方法允许你在对象上设置属性。</p>
</blockquote>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// Object</span></span><br><span class="line"><span class="keyword">let</span> x = &#123;&#125;</span><br><span class="line"><span class="built_in">Reflect</span>.set(x, <span class="string">'a'</span>, <span class="number">1</span>)</span><br><span class="line">log(x) <span class="comment">//&#123; a: 1 &#125;</span></span><br><span class="line"><span class="comment">// Array</span></span><br><span class="line"><span class="comment">// 这里要注意，对数组的操作会截断原数组</span></span><br><span class="line"><span class="keyword">let</span> y = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>]</span><br><span class="line"><span class="built_in">Reflect</span>.set(y, <span class="number">0</span>, <span class="string">'这里是新增的1'</span>)</span><br><span class="line"><span class="built_in">Reflect</span>.set(y, <span class="number">4</span>, <span class="string">'这里是新增的2'</span>)</span><br><span class="line">log(y) <span class="comment">//[ '这里是新增的1', 2, 3, 4, '这里是新增的2' ]</span></span><br><span class="line"><span class="comment">// 当它只有一个参数时</span></span><br><span class="line"><span class="keyword">let</span> z = &#123;&#125;</span><br><span class="line"><span class="built_in">Reflect</span>.set(z)</span><br><span class="line">log(z) <span class="comment">//&#123; undefined: undefined &#125;,如果没有set操作，会打印空（即&#123;&#125;）</span></span><br></pre></td></tr></table></figure>

<h2 id="实现一个简易的数据响应式"><a href="#实现一个简易的数据响应式" class="headerlink" title="实现一个简易的数据响应式"></a>实现一个简易的数据响应式</h2><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// obj 对象  setBind set方法  getLogger get方法</span></span><br><span class="line"><span class="keyword">let</span> onWatch = <span class="function">(<span class="params">obj, setBind, getLogger</span>) =&gt;</span> &#123;</span><br><span class="line">	<span class="keyword">let</span> handler = &#123;</span><br><span class="line">		<span class="comment">// target 是要拦截的目标  </span></span><br><span class="line">		<span class="keyword">get</span>(target, property, receiver) &#123;</span><br><span class="line">			getLogger(target, property)</span><br><span class="line">			<span class="comment">// target 目标对象 property 对应属性 receiver setter方法</span></span><br><span class="line">			<span class="keyword">return</span> <span class="built_in">Reflect</span>.get(target, property, receiver)</span><br><span class="line">		&#125;,</span><br><span class="line">		<span class="keyword">set</span>(target, property, value, receiver) &#123;</span><br><span class="line">			setBind(value, property)</span><br><span class="line">			<span class="comment">// 相当于 vue的 $set</span></span><br><span class="line">			<span class="keyword">return</span> <span class="built_in">Reflect</span>.set(target, property, value)</span><br><span class="line">		&#125;</span><br><span class="line">	&#125;</span><br><span class="line">	<span class="comment">// obj 需要拦截的对象  handler 拦截行为</span></span><br><span class="line">	<span class="keyword">return</span> <span class="keyword">new</span> <span class="built_in">Proxy</span>(obj, handler)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="keyword">let</span> obj = &#123; <span class="attr">a</span>: <span class="number">1</span> &#125;</span><br><span class="line"><span class="keyword">let</span> p = onWatch(</span><br><span class="line">	obj,</span><br><span class="line">	(v, property) =&gt; &#123;</span><br><span class="line">		<span class="built_in">console</span>.log(<span class="string">`监听到属性<span class="subst">$&#123;property&#125;</span>改变为<span class="subst">$&#123;v&#125;</span>`</span>)</span><br><span class="line">	&#125;,</span><br><span class="line">	(target, property) =&gt; &#123;</span><br><span class="line">		<span class="built_in">console</span>.log(<span class="string">`'<span class="subst">$&#123;property&#125;</span>' = <span class="subst">$&#123;target[property]&#125;</span>`</span>)</span><br><span class="line">	&#125;</span><br><span class="line">)</span><br><span class="line">p.a = <span class="number">2</span>   <span class="comment">// 输出 监听到属性a改变为2</span></span><br><span class="line">p.a         <span class="comment">// 输出 'a' = 22</span></span><br></pre></td></tr></table></figure>

<h1 id="map-filter-reduce"><a href="#map-filter-reduce" class="headerlink" title="map filter reduce"></a>map filter reduce</h1><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// map</span></span><br><span class="line"><span class="keyword">let</span> arr = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>]</span><br><span class="line"><span class="keyword">let</span> arr1 = arr.map(<span class="function"><span class="params">x</span> =&gt;</span> x + <span class="number">2</span>)</span><br><span class="line">log(arr) <span class="comment">//[ 1, 2, 3, 4 ]</span></span><br><span class="line">log(arr1) <span class="comment">//[ 3, 4, 5, 6 ]</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// filter</span></span><br><span class="line"><span class="keyword">let</span> arr = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>]</span><br><span class="line"><span class="keyword">let</span> arr1 = arr.filter(<span class="function"><span class="params">x</span> =&gt;</span> x &gt; <span class="number">3</span>)</span><br><span class="line">log(arr) <span class="comment">//[ 1, 2, 3, 4 ]</span></span><br><span class="line">log(arr1) <span class="comment">//4</span></span><br><span class="line"></span><br><span class="line"><span class="comment">//reduce</span></span><br><span class="line"><span class="keyword">let</span> arr = [<span class="number">1</span>, <span class="number">2</span>, <span class="number">3</span>, <span class="number">4</span>]</span><br><span class="line"><span class="keyword">let</span> arr1 = arr.reduce(<span class="function">(<span class="params">acc, cur</span>) =&gt;</span> acc + cur)</span><br><span class="line">log(arr) <span class="comment">//[ 1, 2, 3, 4 ]</span></span><br><span class="line">log(arr1) <span class="comment">//10</span></span><br></pre></td></tr></table></figure>

<h1 id="并发和并行的区别"><a href="#并发和并行的区别" class="headerlink" title="并发和并行的区别"></a>并发和并行的区别</h1><ul>
<li>并发：在一段时间内，通过切换任务完成了任务A、B</li>
<li>并行：在一段时间内，同时完成了A、B</li>
</ul>
<h1 id="如何解决回调地狱"><a href="#如何解决回调地狱" class="headerlink" title="如何解决回调地狱"></a>如何解决回调地狱</h1><ul>
<li>可以使用 generator、promise、async await</li>
</ul>
<h1 id="generator"><a href="#generator" class="headerlink" title="generator"></a>generator</h1><ul>
<li><p>generator的基本用法。next方法返回一个对象，value表示状态值，done表示是否完成遍历</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span>* <span class="title">helloGenerator</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">	<span class="keyword">yield</span> <span class="string">'hello'</span></span><br><span class="line">	<span class="keyword">yield</span> <span class="string">'world'</span></span><br><span class="line">	<span class="keyword">return</span> <span class="string">'ending'</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> hg = helloGenerator()</span><br><span class="line">log(hg.next()) <span class="comment">//&#123; value: 'hello', done: false &#125;</span></span><br><span class="line">log(hg.next()) <span class="comment">//&#123; value: 'world', done: false &#125;</span></span><br><span class="line">log(hg.next()) <span class="comment">//&#123; value: 'ending', done: true &#125;</span></span><br><span class="line">log(hg.next()) <span class="comment">//&#123; value: undefined, done: true &#125;</span></span><br></pre></td></tr></table></figure>
</li>
<li><p>generator的复杂用法</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span>* <span class="title">foo</span>(<span class="params">x</span>) </span>&#123;</span><br><span class="line">	<span class="keyword">let</span> y = <span class="number">2</span> * (<span class="keyword">yield</span> (x + <span class="number">1</span>))</span><br><span class="line">	<span class="keyword">let</span> z = <span class="keyword">yield</span> (y / <span class="number">3</span>)</span><br><span class="line">	<span class="keyword">return</span> (x + y + z)</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> it = foo(<span class="number">5</span>)</span><br><span class="line"><span class="comment">// 参数传入的是5，所以第一个next返回了 （5+1）</span></span><br><span class="line">log(it.next()) <span class="comment">//&#123; value: 6, done: false &#125;</span></span><br><span class="line"><span class="comment">// 如果next()方法带有参数，则这个参数会被当做上一条yield语句的返回值。</span></span><br><span class="line"><span class="comment">// 所以，let y = 2 * (yield (x + 1)) 现在为 let y = 2 * (12)，所以 y=24</span></span><br><span class="line"><span class="comment">// 然后执行 yield (y / 3) ，即24/3=8</span></span><br><span class="line">log(it.next(<span class="number">12</span>)) <span class="comment">//&#123; value: 8, done: false &#125;</span></span><br><span class="line"><span class="comment">// 同上，参数为13，所以z=13，那么 x + y + z == 5 + 24 + 13 =42</span></span><br><span class="line"><span class="comment">// 由于没有yield语句了，所以状态变成了 true</span></span><br><span class="line">log(it.next(<span class="number">13</span>)) <span class="comment">//&#123; value: 42, done: true &#125;</span></span><br></pre></td></tr></table></figure>

</li>
</ul>
<h1 id="Promise"><a href="#Promise" class="headerlink" title="Promise"></a>Promise</h1><h1 id="async和await"><a href="#async和await" class="headerlink" title="async和await"></a>async和await</h1><ul>
<li><p>这是 ES7 新增的语法，如果函数前加上 async，那么就会返回一个 promise 对象。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">x</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">	<span class="keyword">let</span> y = <span class="number">1</span></span><br><span class="line">	<span class="keyword">return</span> y</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 函数x的return  就是返回的 值</span></span><br><span class="line"><span class="comment">// 假如函数x没有return  那么就返回undefined</span></span><br><span class="line">log(x()) <span class="comment">//Promise &#123; 1 &#125;</span></span><br></pre></td></tr></table></figure>
</li>
<li><p>实际上，async await 是 generator 的语法糖。</p>
</li>
<li><p>async 实际上就是 generator 的 <code>*</code></p>
</li>
<li><p>await 实际上就是 yield</p>
</li>
</ul>
<h2 id="相比于generator函数的改进"><a href="#相比于generator函数的改进" class="headerlink" title="相比于generator函数的改进"></a>相比于generator函数的改进</h2><ol>
<li>传统的 generator 的函数调用时需要使用 next 方法，但是现在只需要使用 async。即自带了执行器</li>
<li>更好的语义，async 表示函数是一个异步操作</li>
<li>返回promise</li>
</ol>
<h1 id="常用的定时器"><a href="#常用的定时器" class="headerlink" title="常用的定时器"></a>常用的定时器</h1><h2 id="setTimeout"><a href="#setTimeout" class="headerlink" title="setTimeout"></a>setTimeout</h2><ul>
<li>只执行一次</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="built_in">Set</span> = <span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">	setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">		log(<span class="string">'hello'</span>)</span><br><span class="line">	&#125;, <span class="number">3000</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">Set</span>() <span class="comment">//三秒后打印一次 hello</span></span><br></pre></td></tr></table></figure>

<h2 id="setInterval"><a href="#setInterval" class="headerlink" title="setInterval"></a>setInterval</h2><ul>
<li>每隔一段时间就执行一次</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> <span class="built_in">Set</span> = <span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">	setInterval(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">		log(<span class="string">'hello'</span>)</span><br><span class="line">	&#125;, <span class="number">3000</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="built_in">Set</span>() <span class="comment">// 每隔三秒就打印一次 hello   无限循环</span></span><br></pre></td></tr></table></figure>

<h2 id="requestAnimationFrame"><a href="#requestAnimationFrame" class="headerlink" title="requestAnimationFrame"></a>requestAnimationFrame</h2><ul>
<li>按帧对网页进行重绘，属于 HTML5 API。</li>
<li>由于 setTimeout 、setInterval 都是异步操作，所以间隔的时间不一定准确。</li>
<li>而 requestAnimationFrame 是按帧重绘，一般现在都是60fps，即 16.6ms 执行一次 requestAnimationFrame 函数</li>
</ul>
<h1 id="进程和线程的区别"><a href="#进程和线程的区别" class="headerlink" title="进程和线程的区别"></a>进程和线程的区别</h1><ul>
<li>本质上来讲，进程和线程都是 cpu 工作时间片的一个描述</li>
<li>打开 windows 任务管理器，第一个就是进程，所以进程也就是一个个的应用程序。线程则是更小的单位。</li>
<li>例如打开浏览器，这里面就是创建了一个进程，浏览器的打开又涉及到渲染，js 引擎、http 请求等等，这些小的就是一个个线程</li>
</ul>
<h1 id="JS单线程的好处"><a href="#JS单线程的好处" class="headerlink" title="JS单线程的好处"></a>JS单线程的好处</h1><ul>
<li>在以前，js 被创建出来就是为了浏览器，用来进行页面上的一些交互。一个页面的打开涉及到很多东西 ，比如 HTML DOM 就可以被 js 操作。假如，js 是多线程，那么当在渲染页面时，突然同时操作了 HTML DOM， 就可能发生意想不到的错误。</li>
</ul>
<h1 id="什么是JS执行栈"><a href="#什么是JS执行栈" class="headerlink" title="什么是JS执行栈"></a>什么是JS执行栈</h1><blockquote>
<p>可以把 js 执行栈看成是一个存储函数调用的栈结构</p>
</blockquote>
<ul>
<li><p>简单例子，打印出 1 3 2</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">	log(<span class="number">1</span>)</span><br><span class="line">	bar() <span class="comment">//第二个入栈</span></span><br><span class="line">	log(<span class="number">2</span>)</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">bar</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">	log(<span class="number">3</span>)</span><br><span class="line">&#125;</span><br><span class="line">foo() <span class="comment">//第一个入栈</span></span><br></pre></td></tr></table></figure>
</li>
<li><p>复杂一点例子</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">foo</span>(<span class="params">b</span>)</span>&#123; <span class="comment">// 到了 foo 之后，没有其他函数，就开始出栈</span></span><br><span class="line">	<span class="keyword">let</span> a=<span class="number">5</span></span><br><span class="line">	<span class="keyword">return</span> a*b+<span class="number">10</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">bar</span>(<span class="params">x</span>)</span>&#123;</span><br><span class="line">	<span class="keyword">let</span> y=<span class="number">3</span></span><br><span class="line">	<span class="keyword">return</span> foo(x*y) <span class="comment">// 第二个入栈 log-&gt;bar-&gt;foo</span></span><br><span class="line">&#125;</span><br><span class="line">log(bar(<span class="number">6</span>)) <span class="comment">//第一个入栈 log-&gt;bar</span></span><br></pre></td></tr></table></figure>
</li>
<li><p>递归的例子</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">a</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">	a() <span class="comment">// 第二个入栈，但是由于是递归，会无限调用a函数，而js执行栈是有大小的，所以会出现爆栈，即卡死的状态</span></span><br><span class="line">&#125;</span><br><span class="line">a() <span class="comment">// 第一个入栈</span></span><br></pre></td></tr></table></figure>

</li>
</ul>
<h1 id="异步代码执行顺序"><a href="#异步代码执行顺序" class="headerlink" title="异步代码执行顺序"></a>异步代码执行顺序</h1><blockquote>
<p>既然 JS 中有执行栈，那么异步任务是怎么入栈，先后顺序是怎么样的呢？</p>
</blockquote>
<ul>
<li><p>js 的执行顺序，先同步后异步</p>
</li>
<li><p>异步队列的执行顺序： 先微任务microtask队列，再宏任务macrotask队列</p>
</li>
<li><p>Promise 中的resolve，reject属于微任务队列，setTimeout属于宏任务队列<br>注意以上都是 队列，先进先出。</p>
</li>
<li><p>微任务包括 <code>process.nextTick</code> ，<code>promise</code> ，<code>MutationObserver</code>。</p>
</li>
<li><p>宏任务包括 <code>script</code> ， <code>setTimeout</code> ，<code>setInterval</code> ，<code>setImmediate</code> ，<code>I/O</code> ，<code>UI rendering</code></p>
</li>
<li><p>看看这个复杂的代码，分析一下</p>
</li>
</ul>
<ol>
<li>首先执行整个片段的同步代码</li>
<li>首先执行<code>console.log(&#39;script start&#39;)</code>，然后遇到<code>async1()</code>，就会立马执行<code>await async2()</code>里面的<code>console.log(&#39;async2 end&#39;)</code>。</li>
<li>接着往下执行，由于 setTimeout 为宏任务，所以最后执行，现在被挂起</li>
<li>new Promise 被直接执行，所以<code>console.log(&#39;Promise&#39;)</code></li>
<li>接着执行最后的<code>console.log(&#39;script end&#39;)</code></li>
<li>现在所有的同步代码都执行完了，开始异步代码。</li>
<li>根据队列的先进先出规则，开始执行<code>await async2()</code>后面的<code>console.log(&#39;async1 end&#39;)</code></li>
<li>接着执行<code>resolve()</code>，将 promise 状态改为 resolved，然后执行 then 函数。所以依次执行<code>console.log(&#39;promise1&#39;)</code>和<code>console.log(&#39;promise2&#39;)</code></li>
<li>最后就只剩宏任务了，所以最后执行<code>console.log(&#39;setTimeout&#39;)</code><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 同步</span></span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'script start'</span>) <span class="comment">//1 </span></span><br><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">async1</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">	<span class="keyword">await</span> async2()</span><br><span class="line">	<span class="built_in">console</span>.log(<span class="string">'async1 end'</span>) <span class="comment">//5</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">async</span> <span class="function"><span class="keyword">function</span> <span class="title">async2</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">	<span class="built_in">console</span>.log(<span class="string">'async2 end'</span>) <span class="comment">//2</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 异步 实际上为 promise，微任务</span></span><br><span class="line">async1()</span><br><span class="line"><span class="comment">// 异步 定时器都是宏任务</span></span><br><span class="line">setTimeout(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">	<span class="built_in">console</span>.log(<span class="string">'setTimeout'</span>) <span class="comment">//8</span></span><br><span class="line">&#125;, <span class="number">0</span>)</span><br><span class="line"><span class="comment">// 异步 promise 微任务</span></span><br><span class="line"><span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="params">resolve</span> =&gt;</span> &#123;</span><br><span class="line">	<span class="built_in">console</span>.log(<span class="string">'Promise'</span>) <span class="comment">//3</span></span><br><span class="line">	resolve() <span class="comment">// pengding-&gt;resolved</span></span><br><span class="line">&#125;)</span><br><span class="line">	.then(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">		<span class="built_in">console</span>.log(<span class="string">'promise1'</span>) <span class="comment">//6</span></span><br><span class="line">	&#125;)</span><br><span class="line">	.then(<span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">		<span class="built_in">console</span>.log(<span class="string">'promise2'</span>) <span class="comment">//7</span></span><br><span class="line">	&#125;)</span><br><span class="line"><span class="comment">// 同步</span></span><br><span class="line"><span class="built_in">console</span>.log(<span class="string">'script end'</span>) <span class="comment">//4</span></span><br></pre></td></tr></table></figure>
</li>
</ol>
<ul>
<li>继续看一个复杂的例子</li>
</ul>
<ol>
<li>这是一个立即执行函数，分为三个部分。第一个是宏任务，第二个是promise，第三个是同步任务</li>
<li>所以依次执行<code>console.log(1)</code>和<code>console.log(7)</code>。</li>
<li>接下来就开始分析这个 promise 内部的代码。</li>
<li>第一块中有一个宏任务和微任务，所以先执行<code>Promise.resolve().then(() =&gt; console.log(4))</code></li>
<li>现在第一块的代码只剩下了宏任务，后面第二块的调用需要 resolve() 。所以根据队列的规则，开始执行前面入队的宏任务，执行<code>console.log(0)</code>。</li>
<li>现在开始执行第一块代码内的宏任务。由于内部有同步代码，所以首先执行<code>console.log(3)</code>。接着执行先入队列的 resolve()</li>
<li>现在进入第二块代码。执行同步代码<code>console.log(5)</code>。</li>
<li>剩下的就是微任务和宏任务。根据队列规则，依次开始执行<code>Promise.resolve().then(() =&gt; console.log(2))</code>和<code>Promise.resolve().then(() =&gt; console.log(8))</code></li>
<li>最后只剩下宏任务<code>setTimeout(() =&gt; console.log(6))</code><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line">(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="number">0</span>)</span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="params">resolve</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="number">1</span>)</span><br><span class="line">        setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">            resolve()</span><br><span class="line">            <span class="built_in">Promise</span>.resolve().then(<span class="function"><span class="params">()</span> =&gt;</span> <span class="built_in">console</span>.log(<span class="number">2</span>))</span><br><span class="line">            <span class="built_in">console</span>.log(<span class="number">3</span>)</span><br><span class="line">        &#125;)</span><br><span class="line">        <span class="built_in">Promise</span>.resolve().then(<span class="function"><span class="params">()</span> =&gt;</span> <span class="built_in">console</span>.log(<span class="number">4</span>))</span><br><span class="line">    &#125;).then(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="number">5</span>)</span><br><span class="line">        <span class="built_in">Promise</span>.resolve().then(<span class="function"><span class="params">()</span> =&gt;</span> <span class="built_in">console</span>.log(<span class="number">8</span>))</span><br><span class="line">        setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> <span class="built_in">console</span>.log(<span class="number">6</span>))</span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="number">7</span>)</span><br><span class="line">&#125;)()</span><br></pre></td></tr></table></figure>
</li>
</ol>
<ul>
<li>最后一个例子，具体的过程用一张图来表示<br><img src="/images/59.jpg" alt><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">(<span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">    setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="number">0</span>)</span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="keyword">new</span> <span class="built_in">Promise</span>(<span class="function"><span class="params">resolve</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="number">1</span>)</span><br><span class="line">        setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">            resolve()</span><br><span class="line">            <span class="built_in">Promise</span>.resolve().then(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">                <span class="built_in">console</span>.log(<span class="number">2</span>)</span><br><span class="line">                setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> <span class="built_in">console</span>.log(<span class="number">3</span>))</span><br><span class="line">                <span class="built_in">Promise</span>.resolve().then(<span class="function"><span class="params">()</span> =&gt;</span> <span class="built_in">console</span>.log(<span class="number">4</span>))</span><br><span class="line">            &#125;)</span><br><span class="line">        &#125;)</span><br><span class="line">        <span class="built_in">Promise</span>.resolve().then(<span class="function"><span class="params">()</span> =&gt;</span> <span class="built_in">console</span>.log(<span class="number">5</span>))</span><br><span class="line">    &#125;).then(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">        <span class="built_in">console</span>.log(<span class="number">6</span>)</span><br><span class="line">        <span class="built_in">Promise</span>.resolve().then(<span class="function"><span class="params">()</span> =&gt;</span> <span class="built_in">console</span>.log(<span class="number">7</span>))</span><br><span class="line">        setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> <span class="built_in">console</span>.log(<span class="number">8</span>))</span><br><span class="line">    &#125;)</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="number">9</span>)</span><br><span class="line">&#125;)()</span><br></pre></td></tr></table></figure>

</li>
</ul>
<h1 id="什么是Event-Loop"><a href="#什么是Event-Loop" class="headerlink" title="什么是Event-Loop"></a>什么是Event-Loop</h1><ul>
<li>这是 js 异步的具体解决方案：即先执行所有的函数，如果是同步函数，则直接执行，如果是异步，就要放入异步队列。当所有的同步函数执行完成后，就开始执行异步函数。</li>
<li>要注意，异步函数又分为宏任务和微任务。先执行完所有的微任务，才会执行宏任务。</li>
<li>最后要注意的就是，异步队列的执行顺序为先进先出。</li>
</ul>
<p>一些具体的代码上：</p>
<ol>
<li>当 async 函数执行时，一旦遇到 await 就会先返回，等到异步操作完成后，在接着执行 await 后面的语句</li>
<li>promise 的 then 方法要被调用的话，需要有 resolve() 才行。resolve() 的作用在于修改 promise 的状态</li>
</ol>
<ul>
<li>看一个具体的例子，很简单，但是有几个注意点</li>
</ul>
<ol>
<li>并不是碰到异步代码就放入异步队列，不然的话，这里就会打印 3 1 2。</li>
<li>当碰到第一个 setTimeout 时，它有一个条件是在 100ms 后执行，所以实际上，它并没有被存入到异步队列中，而是在 100ms 后才存入</li>
<li>第二个无延迟，所以直接存入</li>
<li>在完成同步代码后，就会开始轮询异步队列，首先检测到的第二个异步代码，于是直接执行<code>log(2)</code></li>
<li>然后接着继续轮询，在 100ms 后检测到第一个异步代码假如队列，于是执行 <code>log(1)</code></li>
<li>在计算机中，ms 也是很长的单位</li>
<li>但是如果第一个异步代码的条件是 1ms，那么会打印 3 1 2<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">	log(<span class="number">1</span>)</span><br><span class="line">&#125;, <span class="number">100</span>)</span><br><span class="line">setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">	log(<span class="number">2</span>)</span><br><span class="line">&#125;)</span><br><span class="line">log(<span class="number">3</span>)</span><br></pre></td></tr></table></figure>

</li>
</ol>
<h1 id="call-apply-bind"><a href="#call-apply-bind" class="headerlink" title="call apply bind"></a>call apply bind</h1><h2 id="call"><a href="#call" class="headerlink" title="call"></a>call</h2><ul>
<li>调用一个函数，同时可以改变 this 的指向<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> obj = &#123;</span><br><span class="line">	x: <span class="number">1</span>,</span><br><span class="line">	y: <span class="number">2</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">fn</span>(<span class="params">x, y</span>) </span>&#123;</span><br><span class="line">	log(<span class="keyword">this</span>)</span><br><span class="line">	log(x + y)</span><br><span class="line">&#125;</span><br><span class="line">fn() <span class="comment">// window NaN</span></span><br><span class="line">fn.call(obj) <span class="comment">// obj NaN</span></span><br><span class="line">fn.call(obj, <span class="number">1</span>, <span class="number">2</span>) <span class="comment">// obj 3</span></span><br></pre></td></tr></table></figure>

</li>
</ul>
<h2 id="apply"><a href="#apply" class="headerlink" title="apply"></a>apply</h2><ul>
<li>和 call 类似，区别在于 apply 的参数必须是数组<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> obj = &#123;</span><br><span class="line">	x: <span class="number">1</span>,</span><br><span class="line">	y: <span class="number">2</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">fn</span>(<span class="params">x, y</span>) </span>&#123;</span><br><span class="line">	log(<span class="keyword">this</span>)</span><br><span class="line">	log(x + y)</span><br><span class="line">&#125;</span><br><span class="line">fn() <span class="comment">// window NaN</span></span><br><span class="line">fn.apply(obj) <span class="comment">// obj NaN</span></span><br><span class="line">fn.apply(obj, [<span class="number">1</span>, <span class="number">2</span>]) <span class="comment">// obj 3</span></span><br></pre></td></tr></table></figure>

</li>
</ul>
<h2 id="bind"><a href="#bind" class="headerlink" title="bind"></a>bind</h2><ul>
<li>不会调用函数，但是可以改变 this 的指向</li>
<li>返回一个由指定的 this 值和参数改造的原函数的拷贝<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span> obj = &#123;</span><br><span class="line">	x: <span class="number">1</span>,</span><br><span class="line">	y: <span class="number">2</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">fn</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">	log(<span class="keyword">this</span>)</span><br><span class="line">	log(<span class="keyword">this</span>.x + <span class="keyword">this</span>.y)</span><br><span class="line">&#125;</span><br><span class="line">fn() <span class="comment">// window NaN</span></span><br><span class="line"><span class="keyword">let</span> fn1 = fn.bind(obj)</span><br><span class="line">fn1() <span class="comment">// obj 3</span></span><br></pre></td></tr></table></figure>

</li>
</ul>
<h1 id="new原理"><a href="#new原理" class="headerlink" title="new原理"></a>new原理</h1><ul>
<li>面试经常会问 new 在使用时发生了什么，这次就自己实现一个 new 来理解他的工作原理<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">myNew</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">	<span class="comment">// 生成一个新对象</span></span><br><span class="line">	<span class="keyword">let</span> obj = &#123;&#125;</span><br><span class="line">	<span class="comment">// 删除并拿到arguments的第一项</span></span><br><span class="line">	<span class="comment">// arguments是类数组对象</span></span><br><span class="line">	log(<span class="built_in">arguments</span>) <span class="comment">// [Arguments] &#123; '0': [Function: Person], '1': 'xiaoming' &#125;</span></span><br><span class="line">	<span class="comment">// shift() 方法用于把数组的第一个元素从其中删除，并返回第一个元素的值。</span></span><br><span class="line">	<span class="comment">// 由于arguments是类数组对象而不是数组，所以不能直接使用shift</span></span><br><span class="line">	<span class="comment">// 这里巧妙地使用call将shift的this指向了arguments</span></span><br><span class="line">	<span class="keyword">let</span> Con = [].shift.call(<span class="built_in">arguments</span>)</span><br><span class="line">	log(Con) <span class="comment">// [Function: Person]</span></span><br><span class="line">	<span class="comment">// 链接到原型上</span></span><br><span class="line">	<span class="comment">// 让新对象指向构造函数指向的原型对象上</span></span><br><span class="line">	<span class="comment">// 现在的关系是，obj为Con的实例对象</span></span><br><span class="line">	obj.__proto__ = Con.prototype</span><br><span class="line">	<span class="comment">// 绑定this</span></span><br><span class="line">	<span class="keyword">let</span> result = Con.apply(obj, <span class="built_in">arguments</span>)</span><br><span class="line">	<span class="comment">// 返回一个新对象</span></span><br><span class="line">	<span class="keyword">return</span> result <span class="keyword">instanceof</span> <span class="built_in">Object</span> ? result : obj</span><br><span class="line">&#125;</span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">Person</span>(<span class="params">name</span>) </span>&#123;</span><br><span class="line">	<span class="keyword">this</span>.name = name</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">let</span> p = myNew(Person, <span class="string">'xiaoming'</span>, <span class="string">'xxxxx'</span>)</span><br><span class="line">log(p) <span class="comment">//Person &#123; name: 'xiaoming' &#125;</span></span><br></pre></td></tr></table></figure>

</li>
</ul>
<h1 id="通过new创建和字面量创建的差异"><a href="#通过new创建和字面量创建的差异" class="headerlink" title="通过new创建和字面量创建的差异"></a>通过new创建和字面量创建的差异</h1><p>对于创建一个对象来说，更推荐使用字面量的方式创建对象（无论性能上还是可读性）。</p>
<h1 id="一些网上整理的面试题"><a href="#一些网上整理的面试题" class="headerlink" title="一些网上整理的面试题"></a>一些网上整理的面试题</h1><p>这些知识比较繁琐，参考别人的博客即可，主要是记忆。多看多记多背就理解了，不在自己总结。</p>
<p><a href="https://www.cnblogs.com/chenwenhao/p/11267238.html" target="_blank" rel="noopener">浏览器、http 1</a><br><a href="https://segmentfault.com/a/1190000019138192?utm_source=tag-newest" target="_blank" rel="noopener">浏览器、http 2</a><br><a href="https://segmentfault.com/a/1190000020391424?utm_source=tag-newest" target="_blank" rel="noopener">前端经典面试题</a></p>
<h1 id="vue生命周期钩子函数"><a href="#vue生命周期钩子函数" class="headerlink" title="vue生命周期钩子函数"></a>vue生命周期钩子函数</h1><ul>
<li>vue 生命周期就是 vue 实例从创建到销毁的过程。</li>
<li>生命周期有很多事件钩子函数，这些钩子可以使得在控制 vue 实例过程中更加容易形成好的逻辑</li>
<li>生命周期总共分为八个阶段：创建前后、载入前后、更新前后、销毁前后</li>
</ul>
<ol>
<li>beforeCreate：可以在这里放置一个 loading 事件，在加载 vue 实例的时候就会触发</li>
<li>created：初始化完成时的事件可以放在这，比如结束 loading 事件，这里也可以放异步的网络请求</li>
<li>beforeMount：vue 实例的 el 和 data 都已经初始化了，但是还没有挂载，现在时虚拟的 DOM 节点</li>
<li>mounted：vue 实例以及挂载到了真正的 DOM 上，这里可以用来获取 DOM 节点</li>
<li>beforeUpdate：响应式数据在发生变化的时候调用，在虚拟 DOM 重新渲染和打补丁(patch)之前</li>
<li>updated：虚拟 DOM 重新渲染和打补丁(patch)之后调用，这个时候数据已经完成了更新。可以在这里对数据统一处理，但是要避免在这里操作数据 ，防止死循环</li>
<li>beforeDestroy：vue 实例销毁之前调用，可以在这里做一个确认停止或者退出的提示框</li>
<li>destroyed：vue 实例销毁后调用</li>
</ol>
<ul>
<li>另外还有 keep-alive 独有的生命周期，分别为 activated 和 deactivated 。<strong><em>用 keep-alive 包裹的组件在切换时不会进行销毁，而是缓存到内存中并执行 deactivated 钩子函数，命中缓存渲染后会执行 actived 钩子函数。</em></strong></li>
</ul>
<h1 id="vue组件通信"><a href="#vue组件通信" class="headerlink" title="vue组件通信"></a>vue组件通信</h1><h2 id="父子通信"><a href="#父子通信" class="headerlink" title="父子通信"></a>父子通信</h2><ol>
<li>父组件通过 props 传递数据给子组件，子组件通过 emit 发送事件传递数据给父组件，这两种方式是最常用的父子通信实现办法。</li>
<li>另外这两种方式还可以使用语法糖 v-model 来直接实现，因为 v-model 默认会解析成名为 value 的 prop 和名为 input 的事件。这种语法糖的方式是典型的双向绑定，常用于 UI 控件上，但是究其根本，还是通过事件的方法让父组件修改数据。</li>
<li>当然还可以通过访问 $parent 或者 $children 对象来访问组件实例中的方法和数据。</li>
</ol>
<h2 id="兄弟通信"><a href="#兄弟通信" class="headerlink" title="兄弟通信"></a>兄弟通信</h2><ol>
<li>对于这种情况可以通过查找父组件中的子组件实现，也就是 this.$parent.$children，在 $children 中可以通过组件 name 查询到需要的组件实例，然后进行通信。</li>
<li>BUS 总线</li>
</ol>
<h2 id="跨多层次通信"><a href="#跨多层次通信" class="headerlink" title="跨多层次通信"></a>跨多层次通信</h2><p>对于这种情况可以使用 Vue 2.2 新增的 API provide / inject，虽然文档中不推荐直接使用在业务中，但是如果用得好的话还是很有用的。</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 父组件 A</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  provide: &#123;</span><br><span class="line">    data: <span class="number">1</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 子组件 B</span></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  inject: [<span class="string">'data'</span>],</span><br><span class="line">  mounted() &#123;</span><br><span class="line">    <span class="comment">// 无论跨几层都能获得父组件的 data 属性</span></span><br><span class="line">    <span class="built_in">console</span>.log(<span class="keyword">this</span>.data) <span class="comment">// =&gt; 1</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h2 id="任意通信"><a href="#任意通信" class="headerlink" title="任意通信"></a>任意通信</h2><p>可以通过 Vuex 或者 Event Bus 解决任何情况下的通信问题，就是比较麻烦</p>
<h1 id="vue中的-computed-和-watch-区别"><a href="#vue中的-computed-和-watch-区别" class="headerlink" title="vue中的 computed 和 watch 区别"></a>vue中的 computed 和 watch 区别</h1><ul>
<li>computed 是计算属性，依赖其他属性计算值，并且 computed 的值有缓存，只有当计算值变化才会返回内容。</li>
<li>watch 监听到值的变化就会执行回调，在回调中可以进行一些逻辑操作。</li>
</ul>
<h1 id="vue中的-keep-alive-组件有什么作用"><a href="#vue中的-keep-alive-组件有什么作用" class="headerlink" title="vue中的 keep-alive 组件有什么作用"></a>vue中的 keep-alive 组件有什么作用</h1><ul>
<li>如果你需要在组件切换的时候，保存一些组件的状态防止多次渲染，就可以使用 keep-alive 组件包裹需要保存的组件。</li>
</ul>
<h1 id="vue中的-v-show-与-v-if-区别"><a href="#vue中的-v-show-与-v-if-区别" class="headerlink" title="vue中的 v-show 与 v-if 区别"></a>vue中的 v-show 与 v-if 区别</h1><ul>
<li>v-show 只是在 display: none 和 display: block 之间切换。无论初始条件是什么都会被渲染出来，后面只需要切换 CSS，DOM 还是一直保留着的。所以总的来说 v-show 在初始渲染时有更高的开销，但是切换开销很小，更适合于频繁切换的场景。</li>
<li>v-if 的话就得说到 Vue 底层的编译了。当属性初始为 false 时，组件就不会被渲染，直到条件为 true，并且切换条件时会触发销毁/挂载组件，所以总的来说在切换时开销更高，更适合不经常切换的场景。</li>
</ul>
<h1 id="vue组件中-data-什么时候可以使用对象"><a href="#vue组件中-data-什么时候可以使用对象" class="headerlink" title="vue组件中 data 什么时候可以使用对象"></a>vue组件中 data 什么时候可以使用对象</h1><ul>
<li>首先在 js 中，存储对象的变量实际上存储的是一个指针地址。所以，在组件需要复用的时候，就不能将 data 设置为对象。所以需要将 data 写成函数，每次用到就调用一次函数获得新的数据。</li>
<li>当我们使用 new Vue() 的方式的时候，无论我们将 data 设置为对象还是函数都是可以的，因为 new Vue() 的方式是生成一个根组件，该组件不会复用，也就不存在共享 data 的情况了。</li>
</ul>
<h1 id="vue编译过程"><a href="#vue编译过程" class="headerlink" title="vue编译过程"></a>vue编译过程</h1><p>在 vue 的开发中，使用的是模板技术，那么这个模板是怎么编译的呢？并且还能正确的显示在浏览器上</p>
<ul>
<li>首先直接把模板丢到浏览器中肯定是不能运行的，模板只是为了方便开发者进行开发。</li>
<li>Vue 会通过编译器将模板通过几个阶段最终编译为 render 函数，然后通过执行 render 函数生成 Virtual DOM 最终映射为真实 DOM。</li>
<li>这个编译的过程分为三个阶段</li>
</ul>
<ol>
<li>将模板解析为 AST：在第一个阶段中，最主要的事情还是通过各种各样的正则表达式去匹配模板中的内容，然后将内容提取出来做各种逻辑操作，接下来会生成一个最基本的 AST 对象</li>
<li>优化 AST(抽象语法树：它就是所写代码的的树状结构化表现形式。)：</li>
<li>将 AST 转换为 render 函数：其实这一阶段虽然分支有很多，但是最主要的目的就是遍历整个 AST，根据不同的条件生成不同的代码罢了。</li>
</ol>
<h1 id="SPA单页应用的理解"><a href="#SPA单页应用的理解" class="headerlink" title="SPA单页应用的理解"></a>SPA单页应用的理解</h1><blockquote>
<p>SPA仅在页面初始化时加载相应的 HTML CSS JS 文件。当页面加载完成后，用户操作所导致的页面的变化都不会重新加载或跳转网址。而是根据路由机制实现网页内容的变换</p>
</blockquote>
<ul>
<li>优点</li>
</ul>
<ol>
<li>无刷新切换内容，提高用户体验。</li>
<li>符合前后端分离的开发思想，通过ajax异步请求数据接口获取数据，后台只需要负责数据，不用考虑渲染。前端使用vue等MVVM框架渲染数据非常合适。</li>
<li>减轻服务器压力，展示逻辑和数据渲染在前端完成，服务器任务更明确，压力减轻。</li>
<li>后端数据接口可复用，设计JSON格式数据可以在PC、移动端通用。</li>
</ol>
<ul>
<li>缺点</li>
</ul>
<ol>
<li>不利于SEO（搜索引擎优化），应用数据是通过请求接口动态渲染，不利于SEO。</li>
<li>首页加载慢，SPA下大部分的资源需要在首页加载，造成首页白屏等问题。</li>
</ol>
<h1 id="vuex的理解"><a href="#vuex的理解" class="headerlink" title="vuex的理解"></a>vuex的理解</h1><h2 id="为什么要使用vuex"><a href="#为什么要使用vuex" class="headerlink" title="为什么要使用vuex"></a>为什么要使用vuex</h2><ul>
<li>在之前学习的通信方法中，只适合小范围的使用，如果涉及到复杂的交互和大范围的通信，使用  vuex 更好</li>
<li>vuex 是实现组件全局状态管理的一种机制，可以方便的实现组件之间的数据的共享</li>
<li>那么，vuex 到底比传统的通信方法好在哪呢。首先，传统的通信是一对一的，如果中间隔了几个组件，那么如同击鼓传花一般，可能对不相干的组件的状态造成影响。但是 vuex 有自己独立的状态管理机制（store），这个管理机制与组件是一对多的关系，不会对不相干的组件造成影响，所以用起来很方便。</li>
<li>同时，存在 vuex 中的数据也是响应式的，会自动更新。</li>
<li>那么，什么样的数据适合存储到 vuex 中呢。一般情况下， 只有需要共享的数据才有必要，组件私有的数据放在自身的 data 中即可。</li>
</ul>
<h2 id="基本使用步骤"><a href="#基本使用步骤" class="headerlink" title="基本使用步骤"></a>基本使用步骤</h2><ol>
<li><p>安装 vuex 依赖包</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cnpm install vuex -S</span><br></pre></td></tr></table></figure>
</li>
<li><p>导入 vuex </p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> Vuex <span class="keyword">from</span> <span class="string">'vuex'</span></span><br><span class="line">Vue.use(Vuex)</span><br></pre></td></tr></table></figure>
</li>
<li><p>创建 store 对象</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> store=<span class="keyword">new</span> Vuex.Store(&#123;</span><br><span class="line">	<span class="comment">// state中存放的就是全局共享的数据</span></span><br><span class="line">	state:&#123;</span><br><span class="line">		</span><br><span class="line">	&#125;</span><br><span class="line">&#125;)</span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> store</span><br></pre></td></tr></table></figure>
</li>
<li><p>将 stroe 对象挂载到 vue 实例中</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> store <span class="keyword">from</span> <span class="string">'./store/index.js'</span></span><br><span class="line"><span class="keyword">new</span> Vue(&#123;</span><br><span class="line">	el:<span class="string">'#app'</span>,</span><br><span class="line">	render:<span class="function"><span class="params">h</span>=&gt;</span>h(app),</span><br><span class="line">	router,</span><br><span class="line">	<span class="comment">// 将创建的共享数据对象，挂载到 vue 实例</span></span><br><span class="line">	<span class="comment">// 现在所有的组件，就可以从 store 中获取到共享数据了</span></span><br><span class="line">	store</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

</li>
</ol>
<h2 id="核心概念"><a href="#核心概念" class="headerlink" title="核心概念"></a>核心概念</h2><p>先看看官网的图，大概了解一下如何工作，在接在往下看核心概念。</p>
<p><img src="/images/60.png" alt></p>
<h3 id="state"><a href="#state" class="headerlink" title="state"></a>state</h3><ul>
<li>state 是用来提供唯一的公共数据源，所有的共享数据都要统一放到 store 的 state 中进行存储。</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 公共数据源</span></span><br><span class="line">state: &#123;</span><br><span class="line">  count: <span class="number">0</span></span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure>

<ul>
<li>在定义了共享的数据源后，组件怎么获取到这个数据呢？有以下两种方法</li>
</ul>
<ol>
<li><code>this.$store.state.count</code><figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- 在template组件中，可以省略掉这个this，但是最后不要省略 --&gt;</span>    </span><br><span class="line"><span class="tag">&lt;<span class="name">h3</span>&gt;</span>当前的count值:&#123;&#123; this.$store.state.count &#125;&#125;<span class="tag">&lt;/<span class="name">h3</span>&gt;</span></span><br></pre></td></tr></table></figure></li>
<li>首先从 vuex 中按需导入 mapState 函数。然后通过这个 mapState 函数，将当前组件需要的数据，映射为当前组件的 computed 计算属性。然后在 template 中直接使用 <code></code>即可<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 导入mapState函数</span></span><br><span class="line"><span class="keyword">import</span> &#123; mapState &#125; <span class="keyword">from</span> <span class="string">'vuex'</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 将其映射到computed组件中</span></span><br><span class="line">computed: &#123;</span><br><span class="line">	...mapState([<span class="string">'count'</span>])</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

</li>
</ol>
<h3 id="Mutation"><a href="#Mutation" class="headerlink" title="Mutation"></a>Mutation</h3><p>有一个需求是，点击按钮使 count 自增。最简单的方法就是给按钮绑定一个事件，然后该事件使得<code>this.$store.state.count++</code>。但是在 vuex 中，<strong><em>不允许组件直接修改 store 里面的数据！</em></strong></p>
<ul>
<li>mutations 用于变更 store 中的数据。所以，如果要更改count，就要使用 mutation。</li>
<li>那么为什么要这样呢？虽然通过 mutations 操作起来比较繁琐，但是可以几种监控所有的数据变化，在后期数据越来越多，使用 mutations 的收益也会变多。</li>
</ul>
<p>那么如何操作 mutations 呢？</p>
<ol>
<li>定义 mutations<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 用于变更数据</span></span><br><span class="line">mutations: &#123;</span><br><span class="line"><span class="comment">// add函数，用来变更状态</span></span><br><span class="line">  add(state) &#123;</span><br><span class="line">    state.count++</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
<li>在组件中操作 mutations。<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line">&lt;template&gt;</span><br><span class="line">  &lt;div&gt;</span><br><span class="line">    &lt;h3&gt;当前的count值:&#123;&#123; $store.state.count &#125;&#125;&lt;&#x2F;h3&gt;</span><br><span class="line">    &lt;!-- 给按钮绑定 btnAdd 事件 --&gt;</span><br><span class="line">    &lt;button @click&#x3D;&quot;btnAdd&quot;&gt;+1&lt;&#x2F;button&gt;</span><br><span class="line">  &lt;&#x2F;div&gt;</span><br><span class="line">&lt;&#x2F;template&gt;</span><br><span class="line"></span><br><span class="line">&lt;script&gt;</span><br><span class="line">export default &#123;</span><br><span class="line">  data() &#123;</span><br><span class="line">    return &#123;&#125;</span><br><span class="line">  &#125;,</span><br><span class="line">  methods: &#123;</span><br><span class="line">    btnAdd() &#123;</span><br><span class="line">    &#x2F;&#x2F; 当 btnAdd 被触发的时候，通过 this.$store 里面的 commit 方法调用定义在 vuex 中的 mutations 俩面的 add 方法。就完成了 count 的自增。</span><br><span class="line">    &#x2F;&#x2F; commit的作用就是用来调用mutations里面的方法的</span><br><span class="line">      this.$store.commit(&#39;add&#39;)</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br><span class="line">&lt;&#x2F;script&gt;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<ul>
<li>触发 mutations 时传递参数</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 组件内定义的操作mutations的函数，但是传递了一个参数</span></span><br><span class="line"> methods: &#123;</span><br><span class="line">   btnSub() &#123;</span><br><span class="line">     <span class="keyword">this</span>.$store.commit(<span class="string">'subN'</span>, <span class="number">2</span>)</span><br><span class="line">   &#125;</span><br><span class="line"> &#125;</span><br><span class="line">  <span class="comment">// 在vuex中如何接收这个参数呢？</span></span><br><span class="line">  subN(state, step) &#123;</span><br><span class="line">  	state.count -= step</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure>

<ul>
<li>触发 mutations 函数的第二种方法，第一种是 <code>this.$store.commit</code></li>
</ul>
<ol>
<li>首先按需导入 mapMutations 函数</li>
<li>然后通过 mapMutations 函数将需要的 mutations 函数映射为当前组件的 methods 方法。（和 mapState 异曲同工之妙）</li>
<li>通过以下的比较，如果组件想要调用 subN 方法，需要首先给按钮绑定事件，通过触发事件，然后调用 vuex 的 commit 方法，通过 commit 方法去调用 mutations 中的 subN。</li>
<li>如果想要调用 subX，只需要给按钮绑定 mutaions 中的 subX 方法，然后通过 mapMutaions 将 mutations 的 subX 映射到组件的 methods 方法中即可。<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123;mapState,mapMutations&#125; <span class="keyword">from</span> <span class="string">'vuex'</span></span><br><span class="line"></span><br><span class="line">methods: &#123;</span><br><span class="line">	btnSub() &#123;</span><br><span class="line">		<span class="keyword">this</span>.$store.commit(<span class="string">'subN'</span>, <span class="number">2</span>)</span><br><span class="line">	&#125;,</span><br><span class="line">	...mapMutations([<span class="string">'subX'</span>])</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ol>
<ul>
<li>mutation 必须是同步函数：因为当 mutation 触发的时候，回调函数还没有被调用，devtools 不知道什么时候回调函数实际上被调用——实质上任何在回调函数中进行的状态的改变都是不可追踪的。</li>
</ul>
<h3 id="action"><a href="#action" class="headerlink" title="action"></a>action</h3><blockquote>
<p>要通过异步操作变更数据，必须通过 action，而不能使用 mutation。实质上，在 action 中还是使用了 mutation 去变更数据</p>
</blockquote>
<ul>
<li>触发 action 的第一种方法 <code>this.$store.dispatch</code><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">methods:&#123;</span><br><span class="line">	<span class="comment">// 异步操作被触发</span></span><br><span class="line">    btnAddAsync() &#123;</span><br><span class="line">    	<span class="comment">// 通过 this.$store.dispatch 去触发 actions 里面的异步函数 addAsync</span></span><br><span class="line">      <span class="keyword">this</span>.$store.dispatch(<span class="string">'addAsync'</span>)</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 用于异步任务</span></span><br><span class="line">actions: &#123;</span><br><span class="line">  <span class="comment">// 在组件中触发了 addAsync 函数，这里的 context 形参就相当于 vuex 的实例</span></span><br><span class="line">  addAsync(context) &#123;</span><br><span class="line">  <span class="comment">// 在一秒钟之后，通过 context.commit 触发 mutations 中的 add 函数</span></span><br><span class="line">    setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">      context.commit(<span class="string">'add'</span>)</span><br><span class="line">    &#125;, <span class="number">1000</span>)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;,</span><br></pre></td></tr></table></figure>

<ul>
<li>触发 actions 时携带参数</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">btnAddAsyncParams() &#123;</span><br><span class="line">	<span class="keyword">this</span>.$store.dispatch(<span class="string">'addAsyncParams'</span>, <span class="number">5</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">addAsyncParams(context, step) &#123;</span><br><span class="line">	setTimeout(<span class="function"><span class="params">()</span> =&gt;</span> &#123;</span><br><span class="line">		context.commit(<span class="string">'addN'</span>, step)</span><br><span class="line">	&#125;, <span class="number">1000</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<ul>
<li>触发 actions 的第二种方法：mapActions 函数</li>
</ul>
<ol>
<li>先从 vuex 导入 mapActions 函数</li>
<li>通过导入的 mapActions 函数，将需要的 actions 函数映射为当前组件的 methods 方法</li>
</ol>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> &#123; mapActions &#125; <span class="keyword">from</span> <span class="string">'vuex'</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">export</span> <span class="keyword">default</span> &#123;</span><br><span class="line">  <span class="comment">// ...</span></span><br><span class="line">  methods: &#123;</span><br><span class="line">    ...mapActions([</span><br><span class="line">      <span class="string">'increment'</span>, <span class="comment">// 将 `this.increment()` 映射为 `this.$store.dispatch('increment')`</span></span><br><span class="line"></span><br><span class="line">      <span class="comment">// `mapActions` 也支持载荷：</span></span><br><span class="line">      <span class="string">'incrementBy'</span> <span class="comment">// 将 `this.incrementBy(amount)` 映射为 `this.$store.dispatch('incrementBy', amount)`</span></span><br><span class="line">    ]),</span><br><span class="line">    ...mapActions(&#123;</span><br><span class="line">      add: <span class="string">'increment'</span> <span class="comment">// 将 `this.add()` 映射为 `this.$store.dispatch('increment')`</span></span><br><span class="line">    &#125;)</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<h3 id="getter"><a href="#getter" class="headerlink" title="getter"></a>getter</h3><ul>
<li>getter 用于对 store 中的数据进行加工处理形成新的数据返回。<strong><em>注意，它不会修改 store 中的原数组</em></strong></li>
</ul>
<p>特点：</p>
<ol>
<li>getter 可以对 store 中已经存在的数据加工处理之后形成新的数据，类似于 vue 的 computed</li>
<li>store 中数据在发生变化时，getter 加工过的数据也会跟着变化</li>
</ol>
<p>调用方式：</p>
<ol>
<li><code>this.$store.getters.函数名</code></li>
<li>mapGetters ，映射到 computed 中</li>
</ol>
<h2 id="基于vuex的业务功能"><a href="#基于vuex的业务功能" class="headerlink" title="基于vuex的业务功能"></a>基于vuex的业务功能</h2><h1 id="vue-router的理解"><a href="#vue-router的理解" class="headerlink" title="vue-router的理解"></a>vue-router的理解</h1><h2 id="路由的基本概念和原理"><a href="#路由的基本概念和原理" class="headerlink" title="路由的基本概念和原理"></a>路由的基本概念和原理</h2><ul>
<li>路由的本质就是对应关系，在开发中，路由分为<strong>后端路由</strong>和<strong>前端路由</strong></li>
<li>后端路由：本质是 url 请求地址和服务器资源之间的对应关系</li>
<li>前端路由：本质是用户事件与事件处理函数之间的对应关系</li>
</ul>
<h2 id="实现简易的前端路由"><a href="#实现简易的前端路由" class="headerlink" title="实现简易的前端路由"></a>实现简易的前端路由</h2><ul>
<li><p>如何实现一个前端路由呢？在 vue 中，前端路由的实现方式有一种是通过改变 hash 值来实现的。所以难点就是如何监听到 hash 值的变化</p>
</li>
<li><p>可以通过 window 的 onhashchange 事件</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">window</span>.onhashchange=<span class="function"><span class="keyword">function</span>(<span class="params"></span>)</span>&#123;</span><br><span class="line">	<span class="comment">//通过 location.hash 获取到最新的 hash 值</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>实例</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&lt;a href&#x3D;&quot;#aaa&quot;&gt;1&lt;&#x2F;a&gt;</span><br><span class="line">&lt;a href&#x3D;&quot;#bbb&quot;&gt;2&lt;&#x2F;a&gt;</span><br><span class="line">&lt;a href&#x3D;&quot;#ccc&quot;&gt;3&lt;&#x2F;a&gt;</span><br><span class="line">&lt;a href&#x3D;&quot;#ddd&quot;&gt;4&lt;&#x2F;a&gt;</span><br></pre></td></tr></table></figure>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">window</span>.onhashchange = <span class="function"><span class="keyword">function</span> (<span class="params"></span>) </span>&#123;</span><br><span class="line">	<span class="comment">// 依次点击 1 2 3 4</span></span><br><span class="line">	<span class="comment">// 会依次打印出hash值：#aaa #bbb #ccc #ddd</span></span><br><span class="line">	<span class="built_in">console</span>.log(location.hash)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>在获取到了 hash 值后，如何实现页面的切换呢？可以通过 hash 值去实现一个 switch 的判断，然后将值赋值给 vue 实例的数据对象，然后通过动态绑定，从而渲染不同的组件</p>
</li>
</ul>
<h2 id="路由管理器"><a href="#路由管理器" class="headerlink" title="路由管理器"></a>路由管理器</h2><ul>
<li>vue 官方的路由管理器就是 Vue Router。</li>
</ul>
<ol>
<li>支持 HTML5 历史模式和 hash 模式</li>
<li>支持嵌套路由</li>
<li>支持路由参数</li>
<li>支持编程式导航</li>
<li>支持命名路由</li>
</ol>
<h2 id="基本使用"><a href="#基本使用" class="headerlink" title="基本使用"></a>基本使用</h2><p>步骤：</p>
<ol>
<li><p>引入相关库文件，将 vue 和 vue-router 挂载到 window</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- 导入vue --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://cdn.jsdelivr.net/npm/vue/dist/vue.js"</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- 导入vue router --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">script</span> <span class="attr">src</span>=<span class="string">"https://unpkg.com/vue-router/dist/vue-router.js"</span>&gt;</span><span class="tag">&lt;/<span class="name">script</span>&gt;</span></span><br></pre></td></tr></table></figure>
</li>
<li><p>添加路由链接</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- router-link 是vue中提供的标签，默认会被渲染为a标签 --&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- to 属性默认会被渲染为href属性 --&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- to 属性的值默认会被渲染为#开头的hash地址 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">div</span> <span class="attr">id</span>=<span class="string">"app"</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">router-link</span> <span class="attr">to</span>=<span class="string">"user"</span>&gt;</span>user<span class="tag">&lt;/<span class="name">router-link</span>&gt;</span></span><br><span class="line">  <span class="tag">&lt;<span class="name">router-link</span> <span class="attr">to</span>=<span class="string">"register"</span>&gt;</span>register<span class="tag">&lt;/<span class="name">router-link</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">div</span>&gt;</span></span><br></pre></td></tr></table></figure>
</li>
<li><p>添加路由填充位</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!-- 路由填充位也叫路由占位符 --&gt;</span></span><br><span class="line"><span class="comment">&lt;!-- 将来通过路由规则匹配到的组件，将会被渲染到 router-view 所在的位置 --&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">router-view</span>&gt;</span><span class="tag">&lt;/<span class="name">router-view</span>&gt;</span></span><br></pre></td></tr></table></figure>
</li>
<li><p>定义路由组件</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> User = &#123;</span><br><span class="line">	template: <span class="string">'&lt;h1&gt;user&lt;/h1&gt;'</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">const</span> Register = &#123;</span><br><span class="line">	template: <span class="string">'&lt;h1&gt;Register&lt;/h1&gt;'</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
<li><p>配置路由规则并创建路由实例（重要）</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 创建路由实例对象</span></span><br><span class="line"><span class="keyword">let</span> router = <span class="keyword">new</span> VueRouter(&#123;</span><br><span class="line">  <span class="comment">// 创建路由规则</span></span><br><span class="line">  routes: [</span><br><span class="line">    <span class="comment">// 每一个路由规则都是一个配置对象，至少包含path和component属性</span></span><br><span class="line">    <span class="comment">// path：当前路由规则匹配的hash值</span></span><br><span class="line">    <span class="comment">// component：当前路由规则所有展示的组件</span></span><br><span class="line">    &#123;</span><br><span class="line">      path: <span class="string">'/user'</span>,</span><br><span class="line">      component: User</span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      path: <span class="string">'/register'</span>,</span><br><span class="line">      component: Register</span><br><span class="line">    &#125;</span><br><span class="line">  ]</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>
</li>
<li><p>把路由挂载到 vue 实例中</p>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 创建 vm 实例</span></span><br><span class="line"><span class="keyword">const</span> vm = <span class="keyword">new</span> Vue(&#123;</span><br><span class="line">  el: <span class="string">"#app"</span>,</span><br><span class="line">  <span class="comment">// 将router挂载到vm实例</span></span><br><span class="line">  <span class="comment">// 并且要注意，必须在router实例之后，不然会报错，没有进行初始化</span></span><br><span class="line">  router,</span><br><span class="line">  data: &#123;&#125;</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

</li>
</ol>
<h2 id="重定向"><a href="#重定向" class="headerlink" title="重定向"></a>重定向</h2><ul>
<li>路由重定向就是用户在访问 A 的时候，通过路由重定向技术，强制用户跳转到 C，从而展示特定的页面。</li>
<li>通过路由的 redirect 属性，指定一个新的路由地址，可以很方便的设置路由的重定向</li>
</ul>
<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">let</span>  router=<span class="keyword">new</span> VueRouter(&#123;</span><br><span class="line">	routes:[</span><br><span class="line">		&#123;</span><br><span class="line">		<span class="comment">// path表示即将跳转的地址，后面接的redirect就是会被强制跳转的地址</span></span><br><span class="line">			path:<span class="string">'/'</span>,<span class="attr">redirect</span>:<span class="string">'/user'</span></span><br><span class="line">		&#125;,</span><br><span class="line">		&#123;</span><br><span class="line">			path:<span class="string">'/user'</span>,<span class="attr">component</span>:User</span><br><span class="line">		&#125;,</span><br><span class="line">		&#123;</span><br><span class="line">			path:<span class="string">'/register'</span>,<span class="attr">component</span>:Register</span><br><span class="line">		&#125;</span><br><span class="line">	]</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

<h2 id="嵌套路由"><a href="#嵌套路由" class="headerlink" title="嵌套路由"></a>嵌套路由</h2><ul>
<li>嵌套路由的使用场景</li>
</ul>
<ol>
<li>点击父级路由链接显示模板内容</li>
<li>模板内容中又有子级路由链接</li>
<li>点击子级路由链接显示自己模板内容</li>
<li>概括起来就一句话：点击 A 路由，显示出自己的模板，并且同时显示出它的子级路由所显示的模板。有且仅有当点击 A 的时候他才显示出来</li>
</ol>
<ul>
<li>使用</li>
</ul>
<ol>
<li>在父级组件中添加子级路由的链接</li>
<li>并且还需要子级路由的填充位<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> Register = &#123;</span><br><span class="line">  <span class="comment">// template的内容可以使用引号包裹，也可以使用``包裹</span></span><br><span class="line">  <span class="comment">// 必须放置占位符</span></span><br><span class="line">  template: <span class="string">`</span></span><br><span class="line"><span class="string">    &lt;div&gt;</span></span><br><span class="line"><span class="string">      &lt;h1&gt;register&lt;/h1&gt;</span></span><br><span class="line"><span class="string">      &lt;hr/&gt;</span></span><br><span class="line"><span class="string">      &lt;router-link to='/register/tab1'&gt;tab1&lt;/router-link&gt;  </span></span><br><span class="line"><span class="string">      &lt;router-link to='/register/tab2'&gt;tab2&lt;/router-link&gt;  </span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">      &lt;router-view&gt;&lt;/router-view&gt;</span></span><br><span class="line"><span class="string">    &lt;/div&gt;</span></span><br><span class="line"><span class="string">  `</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
<li>在定义完成子级路由后，就需要在父级路由规则中添加 children 属性，里面就是子级路由规则<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  path: <span class="string">'/register'</span>,</span><br><span class="line">  component: Register,</span><br><span class="line">  children: [</span><br><span class="line">    &#123;</span><br><span class="line">      path: <span class="string">'/register/tab1'</span>,</span><br><span class="line">      component: Tab1</span><br><span class="line">    &#125;,</span><br><span class="line">    &#123;</span><br><span class="line">      path: <span class="string">'/register/tab2'</span>,</span><br><span class="line">      component: Tab2</span><br><span class="line">    &#125;</span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
<li>最后依次创建 Tab1，Tab2 两个组件即可</li>
</ol>
<h2 id="动态路由匹配"><a href="#动态路由匹配" class="headerlink" title="动态路由匹配"></a>动态路由匹配</h2><blockquote>
<p>我们经常需要把某种模式匹配到的所有路由，全都映射到同个组件。例如，我们有一个 User 组件，对于所有 ID 各不相同的用户，都要使用这个组件来渲染。那么，我们可以在 vue-router 的路由路径中使用“动态路径参数”(dynamic segment) 来达到这个效果</p>
</blockquote>
<ul>
<li>以上官网对于动态路由匹配的描述的大意即，有多个路由匹配到同一个路由规则的时候，比如用户的登录，有100个用户，那么就会有100个路由，那么就要100个路由规则，并且100个路由规则都是使用的相同的登录组件。这样显然不行，那么，现在动态路由匹配就是解决这个问题。</li>
</ul>
<ol>
<li>首先定义一个路由<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">router-link</span> <span class="attr">to</span>=<span class="string">"/login/:userName"</span>&gt;</span>login<span class="tag">&lt;/<span class="name">router-link</span>&gt;</span></span><br></pre></td></tr></table></figure></li>
<li>定义路由规则，现在，不管 /login/ 后面是什么，都会跳转到者这个组件<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  path: <span class="string">'/login/:userName'</span>,</span><br><span class="line">  component: Login</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
<li>那么如何获取到这个动态参数的具体值呢。可以通过 $route.params.userName 获取<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> Login = &#123;</span><br><span class="line">  template: <span class="string">'&lt;h1&gt;login component &#123;&#123;$route.params.userName&#125;&#125;&lt;/h1&gt;'</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
<li>一个“路径参数”使用冒号 : 标记。当匹配到一个路由时，参数值会被设置到 this.$route.params，可以在每个组件内使用。</li>
<li>关于 this.$router 和 this.$route 的区别。可以发现前者是整个路由，而后者是当前路由<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">mounted() &#123;</span><br><span class="line">    <span class="built_in">console</span>.log(<span class="keyword">this</span>.$router)</span><br><span class="line">    <span class="comment">// VueRouter &#123;app: Vue, apps: Array(1), options: &#123;…&#125;, beforeHooks: Array(0), resolveHooks: Array(0), …&#125;</span></span><br><span class="line">    <span class="built_in">console</span>.log(<span class="keyword">this</span>.$route)</span><br><span class="line">    <span class="comment">//&#123;name: undefined, meta: &#123;…&#125;, path: "/login/xxx", hash: "", query: &#123;…&#125;, …&#125;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

</li>
</ol>
<h2 id="路由组件传递参数"><a href="#路由组件传递参数" class="headerlink" title="路由组件传递参数"></a>路由组件传递参数</h2><ul>
<li>在之前获取动态路由的参数时，使用的是 $route.params 去获取的。但是这种方式与对应的路由形成高度耦合，不够灵活，所以可以使用 props 将组件和路由解耦</li>
</ul>
<ol>
<li>props 的值为布尔属性（最常用）<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> Login = &#123;</span><br><span class="line">  <span class="comment">// 使用props接收路由参数</span></span><br><span class="line">  props: [<span class="string">'userName'</span>],</span><br><span class="line">  template: <span class="string">'&lt;h1&gt;login component &#123;&#123;userName&#125;&#125;&lt;/h1&gt;'</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 路由规则</span></span><br><span class="line">&#123;</span><br><span class="line">  path: <span class="string">'/login/:userName'</span>,</span><br><span class="line">  component: Login,</span><br><span class="line">  <span class="comment">// 如果props设置为true，route.params将会被设置为组件属性</span></span><br><span class="line">  props: <span class="literal">true</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
<li>props 的值为对象类型（如果存在静态参数，就是用这种。但是它不能传递动态参数)<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> Login = &#123;</span><br><span class="line">  <span class="comment">// props为对象</span></span><br><span class="line">  props: [<span class="string">'uname'</span>, <span class="string">'age'</span>],</span><br><span class="line">  template:</span><br><span class="line">    <span class="string">'&lt;h1&gt;login component &#123;&#123;uname+age+$route.params.userName&#125;&#125;&lt;/h1&gt;'</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 路由规则</span></span><br><span class="line">&#123;</span><br><span class="line">  path: <span class="string">'/login/:userName'</span>,</span><br><span class="line">  component: Login,</span><br><span class="line">  <span class="comment">// 如果props设置为对象，它将会被按原样设计为组件属性</span></span><br><span class="line">  props: &#123;</span><br><span class="line">    uname: <span class="string">'edison'</span>,</span><br><span class="line">    age: <span class="number">23</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></li>
<li>props 值为函数类型（想当于第二种的改进，现在可以传递动态参数了)<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> Login = &#123;</span><br><span class="line">  <span class="comment">// props:true,</span></span><br><span class="line">  <span class="comment">// 使用props接收路由参数</span></span><br><span class="line">  <span class="comment">// props: ['uname', 'age'],</span></span><br><span class="line">  props: [<span class="string">'age'</span>, <span class="string">'userName'</span>],</span><br><span class="line">  template: <span class="string">'&lt;h1&gt;login component &#123;&#123;age+userName&#125;&#125;&lt;/h1&gt;'</span></span><br><span class="line">&#125;</span><br><span class="line"><span class="comment">// 路由规则</span></span><br><span class="line">&#123;</span><br><span class="line">  path: <span class="string">'/login/:userName'</span>,</span><br><span class="line">  component: Login,</span><br><span class="line">  <span class="comment">// 如果props是一个函数，那么这个函数接收route对象为自己的形参</span></span><br><span class="line">  props: <span class="function">(<span class="params">route</span>) =&gt;</span> (&#123;</span><br><span class="line">    age: <span class="number">20</span>,</span><br><span class="line">    userName: route.params.userName</span><br><span class="line">  &#125;)</span><br><span class="line">  <span class="comment">//props函数等同于以下</span></span><br><span class="line">  <span class="comment">// props: function (route) &#123;</span></span><br><span class="line">  <span class="comment">// 	return &#123;</span></span><br><span class="line">  <span class="comment">// 		age: 20,</span></span><br><span class="line">  <span class="comment">// 		userName: route.params.userName</span></span><br><span class="line">  <span class="comment">// 	&#125;</span></span><br><span class="line">  <span class="comment">// &#125;</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

</li>
</ol>
<h2 id="命名路由"><a href="#命名路由" class="headerlink" title="命名路由"></a>命名路由</h2><blockquote>
<p>有时候，通过一个名称来标识一个路由显得更方便一些，特别是在链接一个路由，或者是执行一些跳转的时候。你可以在创建 Router 实例的时候，在 routes 配置中给某个路由设置名称。</p>
</blockquote>
<ul>
<li>只需要在 routes 中的任一规则下加上 name 属性即可<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">router-link</span> <span class="attr">:to</span>=<span class="string">"&#123;name:'login',params:&#123;userName:'edison'&#125;&#125;"</span>&gt;</span>命名路由，跳转到login<span class="tag">&lt;/<span class="name">router-link</span>&gt;</span></span><br></pre></td></tr></table></figure>

</li>
</ul>
<h2 id="编程式导航"><a href="#编程式导航" class="headerlink" title="编程式导航"></a>编程式导航</h2><blockquote>
<p>除了使用 <code>&lt;router-link&gt;</code> 创建 a 标签来定义导航链接，我们还可以借助 router 的实例方法，通过编写代码来实现。</p>
</blockquote>
<ul>
<li>在 vue 中，编程式导航 API：</li>
</ul>
<ol>
<li>this.$router.push(‘hash地址’)</li>
<li>this.$router.replace(‘hash地址’)。跟 router.push 很像，唯一的不同就是，它不会向 history 添加新记录，而是跟它的方法名一样 —— 替换掉当前的 history 记录。</li>
<li>this.$router.go(n)。这个方法的参数是一个整数，意思是在 history 记录中向前或者后退多少步</li>
</ol>
<h2 id="导航守卫"><a href="#导航守卫" class="headerlink" title="导航守卫"></a>导航守卫</h2><h2 id="路由懒加载"><a href="#路由懒加载" class="headerlink" title="路由懒加载"></a>路由懒加载</h2><h1 id="对于-MVVM-的理解"><a href="#对于-MVVM-的理解" class="headerlink" title="对于 MVVM 的理解"></a>对于 MVVM 的理解</h1><h1 id="vue-中响应式数据的原理"><a href="#vue-中响应式数据的原理" class="headerlink" title="vue 中响应式数据的原理"></a>vue 中响应式数据的原理</h1><ul>
<li>核心点：Object.defineProperty</li>
<li>在 vue 初始化时，都会传入一个 data，而这个 data 会通过 Object.defineProperty 去遍历，然后重新定义所有的属性，这么做的原因在于，它可以给 data 中的数据添加一个拦截器，在 data 变化时可以被监听到。当页面取到对应的属性时，会进行依赖收集（收集当前组件的 watcher），如果属性发生变化，就会通知相关依赖进行更新操作</li>
</ul>
<p>具体在源码中的过程：</p>
<ol>
<li>首先会有一个 initData 方法，进行数据的初始化。其中调用了 observe 方法，传入用户传入的数据，对其进行一个观测</li>
<li>observe 会进行一个判断，判断这个数据是否被观测过了。如果没有被观测过，就会将需要观测的数据传入 Observer，并且会创建一个新的 Observer 实例</li>
<li>接着，就会判断需要观测的数据是对象还是数组。如果是对象，就会调用 walk 方法</li>
<li>walk 方法里面会对传入的对象数据进行一个遍历，每次遍历都会调用一个 defineReactive 方法</li>
<li>defineReactive 中使用了 Object.defineProperty ，里面定义了 get 和 set。当调用 get 时，会把当前的 watcher 收集到，等到数据变化时，会通知 watcher 去更新数据。当数据更新之后，set 就会判断变化的值和设置的值，不一样的话，就会调用一个核心方法 notify ，触发数据对应的依赖进行更新</li>
</ol>
<h1 id="vue-中如何检测数组的变化"><a href="#vue-中如何检测数组的变化" class="headerlink" title="vue 中如何检测数组的变化"></a>vue 中如何检测数组的变化</h1><ul>
<li>使用了函数劫持的方式，重写了数组的方法</li>
<li>vue 将 data 中的数组，进行了原型链的重写，指向了自己定义的数组原型方法，这样，当调用数组 api 时，可以通知依赖更新，如果数组中存在者引用类型，就会对象数组中的引用类型再次进行监控。</li>
<li>明确一点为什么要重写数组的原型方法。因为数组中很多常用的方法会改写原数组，所以只要使用了这个 api ，就可以去触发更新</li>
<li>还有一点，为什么要对数组中的引用类型再次观测。因为数组很特殊，数组的每一项都可以是引用类型，所以，如果有对象存在，就会深度遍历</li>
<li>这些具体的数组方法为：push pop shift unshift splice sort reverse</li>
</ul>
<p>具体在源码中的过程：</p>
<ol>
<li>首先，有一个 initData 方法，对数据进行初始化，然后调用 observe 方法，传入用户传入的数据</li>
<li>observe 会进行一个判断，判断这个数据是否被观测过了。如果没有被观测过，就会将需要观测的数据传入 Observer，并且会创建一个新的 Observer 实例</li>
<li>在 Observer 中会进行判断，如果是数组类型，就会判断这个数组支不支持原型链，如果支持的话，就会调用一个 protoAugment 方法去改写数组原型方法</li>
<li>protoAugment 非常简单，就是让数组的原型指向 src ，这个 src 就是 arrayMethods，即改写的数组方法（七个）</li>
<li>通过函数劫持，只要这七个方法被调用，就会通知视图跟新，即 notify 方法。里面还有一个细节，因为七个方法中有三个方法是可以新增数据的，那么问题就来了，新增的数据可能是对象。所以就要调用 observeArray 方法去观测</li>
<li>observeArray 会遍历每一项，对每一项都调用 observe 方法去观测数组。那么如果新增的不是对象，是否也会观测呢？在 observe 开头就规定了，如果不是对象，就会 return ，而不进行观测</li>
</ol>
<h1 id="vue-为什么采用异步渲染"><a href="#vue-为什么采用异步渲染" class="headerlink" title="vue 为什么采用异步渲染"></a>vue 为什么采用异步渲染</h1><ul>
<li>因为如果不采用异步更新，那么每次更新数据都会对当前组件进行重新渲染。所以为了性能考虑，vue 会在本轮数据更新之后再去异步更新视图</li>
<li>vue 是组件级更新，即数据变化了，会将整个组件都更新。那么如果更新一个数据就同步渲染，当数据有成百上千时，这么多数据都更新了，那么整个组件难道也更新上百次吗？所以很显然，需要采用异步渲染的方法</li>
<li>一个组件中的数据都是同一个 watcher ，所以，即使很多数据更新了，那么就可以过滤掉相同的 watcher，当所有数据更新完成之后，在统一渲染</li>
<li>核心是 nextTick</li>
</ul>
<p>具体在源码中的过程：</p>
<ol>
<li>在之前，所有的数据变化之后，都会调用一个 notify 方法，通知 watcher 进行更新操作</li>
<li>然后通过遍历，调用 update 方法，里面有一个 queueWatcher 方法，即 watcher 队列。然后将 watcher 放入队列</li>
<li>queueWatcher 方法首先做的就是过滤掉 watcher，因为多个属性依赖同一个 watcher。如果这个 watcher 不存在，就将 watcher 放入队列在下一 tick 进行刷新</li>
</ol>
<h1 id="nextTick实现原理"><a href="#nextTick实现原理" class="headerlink" title="nextTick实现原理"></a>nextTick实现原理</h1><h1 id="vue-中-computed-的特点"><a href="#vue-中-computed-的特点" class="headerlink" title="vue 中 computed 的特点"></a>vue 中 computed 的特点</h1><h1 id="watch-中的-deep：true-是如何实现的"><a href="#watch-中的-deep：true-是如何实现的" class="headerlink" title="watch 中的 deep：true 是如何实现的"></a>watch 中的 deep：true 是如何实现的</h1><h1 id="vue-的生命周期"><a href="#vue-的生命周期" class="headerlink" title="vue 的生命周期"></a>vue 的生命周期</h1><h1 id="输入url到页面展示发生了什么"><a href="#输入url到页面展示发生了什么" class="headerlink" title="输入url到页面展示发生了什么"></a>输入url到页面展示发生了什么</h1><blockquote>
<p>可以通过三个步骤去描述</p>
</blockquote>
<h2 id="网络"><a href="#网络" class="headerlink" title="网络"></a>网络</h2><ol>
<li>假设我要输入 <code>www.baidu.com</code></li>
<li>现代浏览器会在你输入的过程中就开始智能匹配 URL，它会从书签、历史记录等地方，找到已经输入的字符串可能匹配到的 URL，然后智能显示出来，让你补全 URL。</li>
<li>构建一个请求<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">GET &#x2F; HTTP&#x2F;1.1</span><br><span class="line">&#x2F;&#x2F; 请求方法是GET，路径为根路径，HTTP协议版本为1.1</span><br></pre></td></tr></table></figure></li>
<li>检查浏览器是否有缓存，如果有的话就直接返回资源给浏览器进程，没有的话就继续。</li>
<li>接着就开始进行 DNS 解析。互联网每台机器的唯一 ID 是 IP地址，但是 IP地址不方便记忆，所以开发者发明了域名系统（DNS），将 IP地址和域名进行一一对应。</li>
<li>建立 TCP 连接。一共有三个阶段：三次握手建立连接、传输数据、四次挥手断开连接。</li>
<li>发送 HTTP 请求。</li>
<li>服务器处理请求。</li>
<li>响应 HTTP 请求。</li>
</ol>
<h2 id="算法解析"><a href="#算法解析" class="headerlink" title="算法解析"></a>算法解析</h2><ol>
<li>如果响应头中的 Content-Type 是 text/html ，浏览器就会开始解析和渲染。</li>
<li>构建 DOM 树。因为浏览器其实不理解 HTML ，因此要将其解析为 DOM 树。</li>
<li>样式计算。同样的，浏览器也不能理解 CSS ，因此要将其转换为一个结构化的对象，即 styleSheets。</li>
<li>生成布局树。在建立了 DOM 树和 CSSOM 树之后，就要通过浏览器的布局系统去确定每个元素存在的位置，即生成一个布局树。</li>
</ol>
<h2 id="渲染过程"><a href="#渲染过程" class="headerlink" title="渲染过程"></a>渲染过程</h2><ol>
<li>建立图层树</li>
<li>生成绘制列表</li>
<li>生成图块并栅格化</li>
<li>显示器显示内容</li>
</ol>
<h1 id="跨域"><a href="#跨域" class="headerlink" title="跨域"></a>跨域</h1><blockquote>
<p>说到跨域，其实就是因为同源策略的存在。即端口、域名、协议三者必须相同，否则无法通信    </p>
</blockquote>
<ul>
<li>以下为解决方案</li>
</ul>
<ol>
<li>JSONP（只支持 get 请求）</li>
</ol>
<ul>
<li>通过 script 标签的异步加载实现，利用 script 标签不受同源策略的限制，天然可以跨域的特性<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> script = <span class="built_in">document</span>.createElement(<span class="string">'script'</span>)</span><br><span class="line">script.type = <span class="string">'text/javascript'</span></span><br><span class="line">script.src = <span class="string">'https://www.baidu.com'</span> <span class="comment">// 接口地址</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">document</span>.head.appendChild(script)</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="keyword">function</span> <span class="title">jsonp</span>(<span class="params">...res</span>)</span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(res)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<ol start="2">
<li>Hash</li>
</ol>
<ul>
<li>url # 后面的内容就叫 Hash。Hash 改变，页面不会刷新<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 在 A 中伪代码</span></span><br><span class="line"><span class="keyword">const</span> B = <span class="built_in">document</span>.getElementsByTagName(<span class="string">'iframe'</span>)</span><br><span class="line">B.src = B.src + <span class="string">'#'</span> + <span class="string">'data'</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 在 B 中的伪代码</span></span><br><span class="line"><span class="built_in">window</span>.onhashchange = <span class="function"><span class="keyword">function</span>(<span class="params"></span>) </span>&#123;</span><br><span class="line">  <span class="keyword">const</span> &#123; data &#125; = <span class="built_in">window</span>.location</span><br><span class="line">&#125;</span><br><span class="line"><span class="string">``</span><span class="string">` </span></span><br><span class="line"><span class="string"></span></span><br><span class="line"><span class="string">3. postMessage</span></span><br><span class="line"><span class="string">* H5 新增的 postMessage() 方法，可以用来做跨域通信</span></span><br><span class="line"><span class="string">`</span><span class="string">``</span>js</span><br><span class="line"><span class="comment">// 在 A 窗口</span></span><br><span class="line"><span class="keyword">const</span> url = <span class="string">'...'</span></span><br><span class="line"><span class="keyword">const</span> Bwindow = <span class="built_in">window</span>.open(url)</span><br><span class="line">Bwindow.postMessage(<span class="string">'data'</span>, url)</span><br><span class="line"></span><br><span class="line"><span class="comment">// 在 B 窗口</span></span><br><span class="line"><span class="built_in">window</span>.addEventListener(<span class="string">'message'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">event</span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(event.origin) <span class="comment">// A 窗口 url</span></span><br><span class="line">  <span class="built_in">console</span>.log(event.source) <span class="comment">// A 窗口 window 对象</span></span><br><span class="line">  <span class="built_in">console</span>.log(event.data) <span class="comment">// A 窗口传过来的数据</span></span><br><span class="line">&#125;, <span class="literal">false</span>)</span><br></pre></td></tr></table></figure>
</li>
</ul>
<ol start="4">
<li>WebSocket</li>
</ol>
<ul>
<li>WebSocket protocol 是 HTML5 一种新的协议，它实现了浏览器与服务器全双工通信，同时允许跨域通讯，是 server push 技术的一种很好的实现<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">const</span> ws = <span class="keyword">new</span> WebSocket(<span class="string">'wss://echo.websocket.org'</span>)</span><br><span class="line"></span><br><span class="line">ws.onopen = <span class="function"><span class="keyword">function</span>(<span class="params">event</span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">'Connection open ...'</span>)</span><br><span class="line">  ws.send(<span class="string">'Hello WebSockets'</span>)</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">ws.onmessage = <span class="function"><span class="keyword">function</span>(<span class="params">event</span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">'Received Message: '</span>, event.data)</span><br><span class="line">	ws.close()</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">ws.onclose = <span class="function"><span class="keyword">function</span>(<span class="params">event</span>) </span>&#123;</span><br><span class="line">  <span class="built_in">console</span>.log(<span class="string">'Connection closed'</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ul>
<ol start="5">
<li>CORS（现代浏览器普遍跨域解决方案）</li>
</ol>
<ul>
<li>整个 CORS 通信过程都是浏览器自动完成，不需要用户参与。对于开发者来说，CORS 通信与同源的 AJAX 通信没有差别，代码完全一样。浏览器一旦发现 AJAX 请求跨域，就会自动添加一些附加的头信息，有时还会多出一次附加的请求，但用户不会有感觉。因此，实现 CORS 通信的关键是服务器，只要服务器实现了 CORS 接口，就可以跨域通信<figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 以 express 为例</span></span><br><span class="line">app.all(<span class="string">'*'</span>, <span class="function"><span class="keyword">function</span>(<span class="params">req, res, next</span>) </span>&#123;</span><br><span class="line">  res.header(<span class="string">'Access-Control-Allow-Origin'</span>, <span class="string">'*'</span>)</span><br><span class="line">  res.header(<span class="string">'Access-Control-Allow-Headers'</span>, <span class="string">'X-Requested-With'</span>)</span><br><span class="line">  res.header(<span class="string">'Access-Control-Allow-Methods'</span>, <span class="string">'PUT,POST,GET,DELETE,OPTIONS'</span>)</span><br><span class="line">  next()</span><br><span class="line">&#125;)</span><br></pre></td></tr></table></figure>

</li>
</ul>
<h1 id="HTTP-和-HTTPS-的主要区别"><a href="#HTTP-和-HTTPS-的主要区别" class="headerlink" title="HTTP 和 HTTPS 的主要区别"></a>HTTP 和 HTTPS 的主要区别</h1><ol>
<li>HTTP 是超文本传输协议，是明文传输，而 HTTPS 是具有 SSL 的加密传输协议。</li>
<li>HTTP 用 80 端口，HTTPS 用 443 端口</li>
<li>HTTP 的连接是无状态的，而 HTTPS 是由 SSL +HTTP 协议构建的可进行加密传输、身份认证的网络协议，要安全的多。</li>
<li>HTTPS 主要解决了 内容隐私、防篡改、确认对方身份。</li>
</ol>
<h1 id="HTTP-常用状态码"><a href="#HTTP-常用状态码" class="headerlink" title="HTTP 常用状态码"></a>HTTP 常用状态码</h1><ol>
<li>2xx：表示成功</li>
<li>3xx：表示重定向</li>
<li>4xx：表示客户端错误</li>
<li>5xx：表示服务器错误</li>
</ol>

    </div>

    
    
    

      <footer class="post-footer">

        


        
    <div class="post-nav">
      <div class="post-nav-item">
    <a href="/2020/08/10/%E5%BE%AE%E4%BF%A1%E5%B0%8F%E7%A8%8B%E5%BA%8F%E7%9A%84%E6%9C%80%E4%BD%B3%E5%AE%9E%E8%B7%B5/" rel="prev" title="微信小程序最佳实践">
      <i class="fa fa-chevron-left"></i> 微信小程序最佳实践
    </a></div>
      <div class="post-nav-item">
    <a href="/2020/11/02/%E6%B7%B1%E5%85%A5%E7%90%86%E8%A7%A3vue%E7%BB%84%E4%BB%B6/" rel="next" title="深入理解vue组件">
      深入理解vue组件 <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  

  </div>


          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#原始类型有哪儿几种"><span class="nav-number">1.</span> <span class="nav-text">原始类型有哪儿几种</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#null-是对象吗"><span class="nav-number">2.</span> <span class="nav-text">null 是对象吗</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#对象类型和原始类型的不同"><span class="nav-number">3.</span> <span class="nav-text">对象类型和原始类型的不同</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#如果函数参数是对象会发生什么"><span class="nav-number">4.</span> <span class="nav-text">如果函数参数是对象会发生什么</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#typeof-和-instanceof-区别"><span class="nav-number">5.</span> <span class="nav-text">typeof 和 instanceof 区别</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#构造函数和原型"><span class="nav-number">6.</span> <span class="nav-text">构造函数和原型</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#构造函数"><span class="nav-number">6.1.</span> <span class="nav-text">构造函数</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#构造函数的成员概念"><span class="nav-number">6.2.</span> <span class="nav-text">构造函数的成员概念</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#构造函数存在的问题"><span class="nav-number">6.3.</span> <span class="nav-text">构造函数存在的问题</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#prototype-amp-proto"><span class="nav-number">6.4.</span> <span class="nav-text">prototype &amp; proto</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#constructor-NaN"><span class="nav-number">6.5.</span> <span class="nav-text">constructor</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#原型链"><span class="nav-number">6.6.</span> <span class="nav-text">原型链</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#关于-this-的总结"><span class="nav-number">7.</span> <span class="nav-text">关于 this 的总结</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#指向性"><span class="nav-number">7.1.</span> <span class="nav-text">指向性</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#箭头函数中的-this"><span class="nav-number">7.2.</span> <span class="nav-text">箭头函数中的 this</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#this-的流程图"><span class="nav-number">7.3.</span> <span class="nav-text">this 的流程图</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#和-的区别"><span class="nav-number">8.</span> <span class="nav-text">&#x3D;&#x3D;和&#x3D;&#x3D;&#x3D;的区别</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#闭包"><span class="nav-number">9.</span> <span class="nav-text">闭包</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#什么是浅拷贝，以及如何实现"><span class="nav-number">10.</span> <span class="nav-text">什么是浅拷贝，以及如何实现</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#Object-assign"><span class="nav-number">10.1.</span> <span class="nav-text">Object.assign</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#展开运算符-…"><span class="nav-number">10.2.</span> <span class="nav-text">展开运算符 …</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#什么是深拷贝，以及如何实现"><span class="nav-number">11.</span> <span class="nav-text">什么是深拷贝，以及如何实现</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#使用JSON-parse"><span class="nav-number">11.1.</span> <span class="nav-text">使用JSON.parse</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#使用递归实现简易深拷贝"><span class="nav-number">11.2.</span> <span class="nav-text">使用递归实现简易深拷贝</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Lodash"><span class="nav-number">11.3.</span> <span class="nav-text">Lodash</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#什么是变量提升"><span class="nav-number">12.</span> <span class="nav-text">什么是变量提升</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#通过一张图解释"><span class="nav-number">12.1.</span> <span class="nav-text">通过一张图解释</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#什么是暂时性死区"><span class="nav-number">13.</span> <span class="nav-text">什么是暂时性死区</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#var-let-const的区别"><span class="nav-number">14.</span> <span class="nav-text">var let const的区别</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#为什么要使用模块化"><span class="nav-number">15.</span> <span class="nav-text">为什么要使用模块化</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#es6-的模块化"><span class="nav-number">16.</span> <span class="nav-text">es6 的模块化</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#export"><span class="nav-number">16.1.</span> <span class="nav-text">export</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#输出变量"><span class="nav-number">16.1.1.</span> <span class="nav-text">输出变量</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#输出函数或类"><span class="nav-number">16.1.2.</span> <span class="nav-text">输出函数或类</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#import"><span class="nav-number">16.2.</span> <span class="nav-text">import</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#Proxy"><span class="nav-number">17.</span> <span class="nav-text">Proxy</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#Reflect-get"><span class="nav-number">17.1.</span> <span class="nav-text">Reflect.get()</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#Reflect-set"><span class="nav-number">17.2.</span> <span class="nav-text">Reflect.set()</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#实现一个简易的数据响应式"><span class="nav-number">17.3.</span> <span class="nav-text">实现一个简易的数据响应式</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#map-filter-reduce"><span class="nav-number">18.</span> <span class="nav-text">map filter reduce</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#并发和并行的区别"><span class="nav-number">19.</span> <span class="nav-text">并发和并行的区别</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#如何解决回调地狱"><span class="nav-number">20.</span> <span class="nav-text">如何解决回调地狱</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#generator"><span class="nav-number">21.</span> <span class="nav-text">generator</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#Promise"><span class="nav-number">22.</span> <span class="nav-text">Promise</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#async和await"><span class="nav-number">23.</span> <span class="nav-text">async和await</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#相比于generator函数的改进"><span class="nav-number">23.1.</span> <span class="nav-text">相比于generator函数的改进</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#常用的定时器"><span class="nav-number">24.</span> <span class="nav-text">常用的定时器</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#setTimeout"><span class="nav-number">24.1.</span> <span class="nav-text">setTimeout</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#setInterval"><span class="nav-number">24.2.</span> <span class="nav-text">setInterval</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#requestAnimationFrame"><span class="nav-number">24.3.</span> <span class="nav-text">requestAnimationFrame</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#进程和线程的区别"><span class="nav-number">25.</span> <span class="nav-text">进程和线程的区别</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#JS单线程的好处"><span class="nav-number">26.</span> <span class="nav-text">JS单线程的好处</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#什么是JS执行栈"><span class="nav-number">27.</span> <span class="nav-text">什么是JS执行栈</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#异步代码执行顺序"><span class="nav-number">28.</span> <span class="nav-text">异步代码执行顺序</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#什么是Event-Loop"><span class="nav-number">29.</span> <span class="nav-text">什么是Event-Loop</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#call-apply-bind"><span class="nav-number">30.</span> <span class="nav-text">call apply bind</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#call"><span class="nav-number">30.1.</span> <span class="nav-text">call</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#apply"><span class="nav-number">30.2.</span> <span class="nav-text">apply</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#bind"><span class="nav-number">30.3.</span> <span class="nav-text">bind</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#new原理"><span class="nav-number">31.</span> <span class="nav-text">new原理</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#通过new创建和字面量创建的差异"><span class="nav-number">32.</span> <span class="nav-text">通过new创建和字面量创建的差异</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#一些网上整理的面试题"><span class="nav-number">33.</span> <span class="nav-text">一些网上整理的面试题</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#vue生命周期钩子函数"><span class="nav-number">34.</span> <span class="nav-text">vue生命周期钩子函数</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#vue组件通信"><span class="nav-number">35.</span> <span class="nav-text">vue组件通信</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#父子通信"><span class="nav-number">35.1.</span> <span class="nav-text">父子通信</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#兄弟通信"><span class="nav-number">35.2.</span> <span class="nav-text">兄弟通信</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#跨多层次通信"><span class="nav-number">35.3.</span> <span class="nav-text">跨多层次通信</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#任意通信"><span class="nav-number">35.4.</span> <span class="nav-text">任意通信</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#vue中的-computed-和-watch-区别"><span class="nav-number">36.</span> <span class="nav-text">vue中的 computed 和 watch 区别</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#vue中的-keep-alive-组件有什么作用"><span class="nav-number">37.</span> <span class="nav-text">vue中的 keep-alive 组件有什么作用</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#vue中的-v-show-与-v-if-区别"><span class="nav-number">38.</span> <span class="nav-text">vue中的 v-show 与 v-if 区别</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#vue组件中-data-什么时候可以使用对象"><span class="nav-number">39.</span> <span class="nav-text">vue组件中 data 什么时候可以使用对象</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#vue编译过程"><span class="nav-number">40.</span> <span class="nav-text">vue编译过程</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#SPA单页应用的理解"><span class="nav-number">41.</span> <span class="nav-text">SPA单页应用的理解</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#vuex的理解"><span class="nav-number">42.</span> <span class="nav-text">vuex的理解</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#为什么要使用vuex"><span class="nav-number">42.1.</span> <span class="nav-text">为什么要使用vuex</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#基本使用步骤"><span class="nav-number">42.2.</span> <span class="nav-text">基本使用步骤</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#核心概念"><span class="nav-number">42.3.</span> <span class="nav-text">核心概念</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#state"><span class="nav-number">42.3.1.</span> <span class="nav-text">state</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#Mutation"><span class="nav-number">42.3.2.</span> <span class="nav-text">Mutation</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#action"><span class="nav-number">42.3.3.</span> <span class="nav-text">action</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#getter"><span class="nav-number">42.3.4.</span> <span class="nav-text">getter</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#基于vuex的业务功能"><span class="nav-number">42.4.</span> <span class="nav-text">基于vuex的业务功能</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#vue-router的理解"><span class="nav-number">43.</span> <span class="nav-text">vue-router的理解</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#路由的基本概念和原理"><span class="nav-number">43.1.</span> <span class="nav-text">路由的基本概念和原理</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#实现简易的前端路由"><span class="nav-number">43.2.</span> <span class="nav-text">实现简易的前端路由</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#路由管理器"><span class="nav-number">43.3.</span> <span class="nav-text">路由管理器</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#基本使用"><span class="nav-number">43.4.</span> <span class="nav-text">基本使用</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#重定向"><span class="nav-number">43.5.</span> <span class="nav-text">重定向</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#嵌套路由"><span class="nav-number">43.6.</span> <span class="nav-text">嵌套路由</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#动态路由匹配"><span class="nav-number">43.7.</span> <span class="nav-text">动态路由匹配</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#路由组件传递参数"><span class="nav-number">43.8.</span> <span class="nav-text">路由组件传递参数</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#命名路由"><span class="nav-number">43.9.</span> <span class="nav-text">命名路由</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#编程式导航"><span class="nav-number">43.10.</span> <span class="nav-text">编程式导航</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#导航守卫"><span class="nav-number">43.11.</span> <span class="nav-text">导航守卫</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#路由懒加载"><span class="nav-number">43.12.</span> <span class="nav-text">路由懒加载</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#对于-MVVM-的理解"><span class="nav-number">44.</span> <span class="nav-text">对于 MVVM 的理解</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#vue-中响应式数据的原理"><span class="nav-number">45.</span> <span class="nav-text">vue 中响应式数据的原理</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#vue-中如何检测数组的变化"><span class="nav-number">46.</span> <span class="nav-text">vue 中如何检测数组的变化</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#vue-为什么采用异步渲染"><span class="nav-number">47.</span> <span class="nav-text">vue 为什么采用异步渲染</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#nextTick实现原理"><span class="nav-number">48.</span> <span class="nav-text">nextTick实现原理</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#vue-中-computed-的特点"><span class="nav-number">49.</span> <span class="nav-text">vue 中 computed 的特点</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#watch-中的-deep：true-是如何实现的"><span class="nav-number">50.</span> <span class="nav-text">watch 中的 deep：true 是如何实现的</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#vue-的生命周期"><span class="nav-number">51.</span> <span class="nav-text">vue 的生命周期</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#输入url到页面展示发生了什么"><span class="nav-number">52.</span> <span class="nav-text">输入url到页面展示发生了什么</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#网络"><span class="nav-number">52.1.</span> <span class="nav-text">网络</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#算法解析"><span class="nav-number">52.2.</span> <span class="nav-text">算法解析</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#渲染过程"><span class="nav-number">52.3.</span> <span class="nav-text">渲染过程</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#跨域"><span class="nav-number">53.</span> <span class="nav-text">跨域</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#HTTP-和-HTTPS-的主要区别"><span class="nav-number">54.</span> <span class="nav-text">HTTP 和 HTTPS 的主要区别</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#HTTP-常用状态码"><span class="nav-number">55.</span> <span class="nav-text">HTTP 常用状态码</span></a></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
  <p class="site-author-name" itemprop="name">Edison</p>
  <div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/archives/">
        
          <span class="site-state-item-count">124</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/categories/">
          
        <span class="site-state-item-count">21</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/tags/">
          
        <span class="site-state-item-count">19</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>



      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

<div class="copyright">
</div>
  <div class="powered-by">山高水远  一定相见
  </div>
<div></div>
<div class="theme-info">
  <div class="powered-by"></div>
  <span class="post-count">至今已写107.1k字</span>
</div>

        








      </div>
    </footer>
  </div>

  
  <script src="/lib/anime.min.js"></script>
  <script src="/lib/velocity/velocity.min.js"></script>
  <script src="/lib/velocity/velocity.ui.min.js"></script>

<script src="/js/utils.js"></script>

<script src="/js/motion.js"></script>


<script src="/js/schemes/pisces.js"></script>


<script src="/js/next-boot.js"></script>




  















  

  

</body>
</html>
